From 1b7f038498bcaaf0a1f09e213be8f69dde1e8eaa Mon Sep 17 00:00:00 2001 From: Bruce M Simpson Date: Thu, 8 Mar 2007 15:26:54 +0000 Subject: [PATCH] Fix IP_SENDSRCADDR semantics. * To use this option with a UDP socket, it must be bound to a local port, and INADDR_ANY, to disallow possible collisions with existing udp inpcbs bound to the same port on other interfaces at send time. * If the socket is bound to INADDR_ANY, specifying IP_SENDSRCADDR with INADDR_ANY will be rejected as it is ambiguous. * If the socket is bound to an address other than INADDR_ANY, specifying IP_SENDSRCADDR with INADDR_ANY will be disallowed by in_pcbbind_setup(). Reviewed by: silence on -net Tested with: src/tools/regression/netinet/ipbroadcast MFC after: 4 days --- sys/netinet/udp_usrreq.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 2743cf74183..0966f2e842e 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -747,7 +747,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, return (EMSGSIZE); } - src.sin_addr.s_addr = INADDR_ANY; + src.sin_family = 0; if (control != NULL) { /* * XXX: Currently, we assume all the optional information is @@ -797,7 +797,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, return (error); } - if (src.sin_addr.s_addr != INADDR_ANY || addr != NULL) { + if (src.sin_family == AF_INET || addr != NULL) { INP_INFO_WLOCK(&udbinfo); unlock_udbinfo = 1; } else @@ -808,10 +808,17 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, mac_create_mbuf_from_inpcb(inp, m); #endif + /* + * If the IP_SENDSRCADDR control message was specified, override the + * source address for this datagram. Its use is invalidated if the + * address thus specified is incomplete or clobbers other inpcbs. + */ laddr = inp->inp_laddr; lport = inp->inp_lport; - if (src.sin_addr.s_addr != INADDR_ANY) { - if (lport == 0) { + if (src.sin_family == AF_INET) { + if ((lport == 0) || + (laddr.s_addr == INADDR_ANY && + src.sin_addr.s_addr == INADDR_ANY)) { error = EINVAL; goto release; }