Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 07 Mar 2007 12:31:02 +0000
From:      "Bruce M. Simpson" <bms@FreeBSD.org>
To:        "Bruce M. Simpson" <bms@FreeBSD.org>
Cc:        Andre Oppermann <andre@freebsd.org>, net@FreeBSD.org
Subject:   Re: Inconsistencies with IP_ONESBCAST and/or IP_SENDSRCADDR
Message-ID:  <45EEB086.3050409@FreeBSD.org>
In-Reply-To: <45E6D70C.10104@FreeBSD.org>
References:  <45C0CA5D.5090903@incunabulum.net> <45E6BEE0.2050307@FreeBSD.org>	<45E6C22D.7060200@freebsd.org> <45E6D70C.10104@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------070900070803040605090309
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Bruce M. Simpson wrote:
>
> Dealing with dhclient is a separate issue -- here, something like 
> IP_SENDIF needs to be introduced, as we are truly in an 'ip 
> unnumbered' situation -- ie the ifnet MAY not yet have been assigned 
> an IPv4 address at all, and IP_SENDSRCADDR implies that you are source 
> routing in the local stack by passing the address of a numbered interface 
I have just committed a change in bms_netdev which enforces strict
and better defined semantics for the IP_SENDSRCADDR option in udp_output().

This fits one of the main intended use cases of this option, e.g. a routing
daemon, bound to 0.0.0.0 and a non-ephemeral port, which needs to
explicitly override the hard-coded source selection policy in ip_output()
to send an undirected broadcast on a numbered interface.

It also fits a use case whereby a bound socket may wish to temporarily
ask for default source selection policy by specifying INADDR_ANY, although
this needs to be reviewed and tested further; I believe in_pcbbind_setup()
will detect a collision in this case.

We always obtain the inp_info write lock if IP_SENDSRCADDR was specified,
in case we need to temporarily re-bind laddr.

Pseudo-conditions as follows.

IP_SENDSRCADDR with lport NOT BOUND is NOT OK.
We should never try to persistently bind a socket which is not bound unless
we are bind(2).

IP_SENDSRCADDR with !INADDR_ANY when laddr is NOT BOUND is OK.
It means override the source selection logic and use src.sin_addr instead.

IP_SENDSRCADDR with INADDR_ANY when laddr is BOUND is OK; it
It means override the bound address and use source selection logic instead.

IP_SENDSRCADDR with INADDR_ANY when laddr is BOUND is OK.
It means override the bound address and use source selection logic instead.

IP_SENDSRCADDR with INADDR_ANY when laddr is NOT BOUND is NOT OK.
It means no valid source is specified.


Regards,
BMS

--------------070900070803040605090309
Content-Type: text/x-patch;
 name="ipsendsrcaddr.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="ipsendsrcaddr.diff"

--- //depot/vendor/freebsd/src/sys/netinet/udp_usrreq.c	2007/02/20 10:22:30
+++ //depot/user/bms/netdev/sys/netinet/udp_usrreq.c	2007/03/07 12:28:16
@@ -747,7 +747,8 @@
 		return (EMSGSIZE);
 	}
 
-	src.sin_addr.s_addr = INADDR_ANY;
+	bzero(&src, sizeof(src));
+
 	if (control != NULL) {
 		/*
 		 * XXX: Currently, we assume all the optional information is
@@ -777,12 +778,10 @@
 					error = EINVAL;
 					break;
 				}
-				bzero(&src, sizeof(src));
 				src.sin_family = AF_INET;
 				src.sin_len = sizeof(src);
-				src.sin_port = inp->inp_lport;
 				src.sin_addr = *(struct in_addr *)CMSG_DATA(cm);
 				break;
 			default:
 				error = ENOPROTOOPT;
 				break;
@@ -797,7 +796,7 @@
 		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
@@ -810,11 +809,20 @@
 
 	laddr = inp->inp_laddr;
 	lport = inp->inp_lport;
-	if (src.sin_addr.s_addr != INADDR_ANY) {
-		if (lport == 0) {
+
+	/*
+	 * 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.
+	 */
+	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;
 		}
+		src.sin_port = lport;
 		error = in_pcbbind_setup(inp, (struct sockaddr *)&src,
 		    &laddr.s_addr, &lport, td->td_ucred);
 		if (error)

--------------070900070803040605090309--



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