Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 Jan 2008 16:32:59 +0100
From:      Fredrik Lindberg <fli@shapeshifter.se>
To:        "Bruce M. Simpson" <bms@FreeBSD.org>
Cc:        freebsd-net@freebsd.org
Subject:   Re: Unexpected multicast IPv4 socket behavior
Message-ID:  <4788DDAB.7080408@shapeshifter.se>
In-Reply-To: <4788B90A.2080901@FreeBSD.org>
References:  <47889F53.4010605@shapeshifter.se> <4788B90A.2080901@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Bruce M. Simpson wrote:
>>
>> I find the following socket behavior a bit unexpected. Multicast from
>> an IPv4 socket (with IP_MULTICAST_IF set) with its source address bound
>> to INADDR_ANY only works if there is a default route defined, otherwise
>> send() returns ENETUNREACH.
>>
>> Default route set, src INADDR_ANY : Works
>> Default route set, src bind() to interface address : Works
>> No default route, src INADDR_ANY : Returns ENETUNREACH
>> No default route, src bind() to interface address : Works
> 
> Totally expected behaviour. There's no way for the stack to know which 
> interface to originate the traffic from in the case where there is no 
> default route, and no IP layer source information elsewhere in the stack.
> 

I would expect this _without_ IP_MULTICAST_IF set, however as I said
the interface had been explicitly set with IP_MULTICAST_IF in all 4
cases, so there indeed is enough information in the stack to send
the packet.

It seems that my test case got stripped of the mail, this was supposed
to be attached to the original post. So just for the record
http://manticore.h3q.net/~fli/multicast.c

> It could be argued that case 3 is in fact an abuse of the APIs. In IPv6, 
> the use of multicast requires that you create a socket and bind to the 
> interface where you wish to send and receive the channel. This is 
> reasonable because both IGMP and MLD require that their group state 
> traffic is bound to a specific address. Thus the glaring holes in IGMP 
> due to the lack of IPv4 link-local addressing.
> 
> The newer multicast APIs in fact require you to do this, precisely to 
> avoid this ambiguity. As such IP_MULTICAST_IF should be considered 
> legacy -- however -- as we've seen, there's a lack of knowledge out 
> there about exactly how this stuff is supposed to work.
> 

If IP_MULTICAST_IF should be considered legacy, I'll move away from it.
But, as you said, there is probably a lack of knowledge on how the
APIs should be used and I have never seen anyone or any document
(maybe I haven't looked hard enough) that suggests that this usage is
deprecated.

>>
>> In all cases IP_MULTICAST_IF was set to the outgoing interface and
>> IP_ADD_MEMBERSHIP was properly called. IGMP membership reports
>> were seen on the link in all cases.
> 
> Now, if you are explicitly telling the stack which interface to use with 
> IP_MULTICAST_IF, and you are seeing the regression in case 3 above, THAT 
> looks like a bug.
> 

Yes, that was the whole point.

>>
>> I believe the cause of this (unless this is the expected behavior?)
>> is in in_pcbconnect_setup() (netinet/in_pcb.c) [1].
>> The check for a multicast destination address is run after the attempt
>> to get the source address by finding a directly connected interface,
>> this check also returns ENETUNREACH if it fails (which it does for the
>> destination 224.0.0.0/24 if no default route is set).
> 
> But but but. Sends to 224.0.0.0/*24* should never fail as it is strictly 
> scoped to a link, and does not require any IPv4 route information. This 
> is the lonesome kicker -- IP needs to know where to source the send 
> from, however, you've told it to already with IP_MULTICAST_IF, so there 
> is definitely a bug.

I know that 224.0.0.0/24 is link-local, I just happened to use that as
a test case. But I wouldn't expect anything in 224.0.0.0/4 to fail
_with_ IP_MULTICAST_IF set.

> 
> See the IN_LOCAL_GROUP() macro in -CURRENT's netinet/in.h for how to 
> check for 224.0.0.0/24 in code.
> 
> In fact we should probably disallow multicast sends to this address when 
> the socket HAS NOT been bound, except of course for the case where the 
> interface is unnumbered -- but we still need a means of telling the 
> stack about this case. The answer might be something called IP_SENDIF... 
> Linux uses SO_BINDTODEVICE for this. It's a case of sitting down and 
> doing it.

For the purpose of avoiding sends to 224.0.0.0/24 to go via
the default route?

IP_SENDIF/SO_BINDTODEVICE seems to show up from time to time, is
the only reason that it hasn't been implemented simply that nobody
has done it?

Fredrik



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