tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: bind() to IPv6 link-local multicast group gives EADDRNOTAVAIL



On 2014-07-24 10:06, Motoyuki OHMORI wrote:
> Hi,
> 
> I guess that in6_pcbind_addr() should always reject binding to a multicast
> address regardless of a socket type, and bind() should be used to determine
> a source address.

Refusing to bind() to a multicast address is unusual, and goes against
RFC 3493 and Stevens' UNIX Network Programming vol. 1.

Note that an application might want to perform the following tasks:

  1. join a group
  2. specify the source IP address for an outgoing UDP packet (or let
     the kernel choose)
  3. specify the destination IP address that must be in an incoming
     UDP packet for it to be received by the socket (or accept any
     destination IP address)

Task #1 is accomplished via the straightforward IPV6_JOIN_GROUP sockopt.

Accomplishing tasks #2 and #3 is messy, particularly for multicast.  For
unicast, bind() is used to both set the source IP address and limit the
destination IP address, though it can't do one without also doing the
other.  For multicast, other operating systems use bind() to limit the
destination IP address to a particular multicast group, but it can't
also set the source IP address.  (RFC 4291 says that the source address
can't be a multicast address.)  Other mechanisms must be used to force a
particular source address, e.g., create and use a second socket for
transmission or use the advanced APIs described in RFCs 3542 and 5014.

> 
> Instead, we need to join an IP multicast address group on an interface that
> would cause the interface to raise received multicast packets to a kernel.
> I am, then, afraid that binding to a multicast address seems not to be useful,
> and that the current source is correct.

Binding to a multicast address prevents an application from being
confused by packets sent to other destinations.

For example, suppose application #1 joins ff02::1234%wm0 and binds to IP
address ff02::1234%wm0 and UDP port 49152.  Application #2 joins
ff0e::5678 and binds to UDP port 49152 but does NOT bind to ff0e::5678.
 In this scenario, application #2 will receive packets destined to
application #1's group even though application #2 never asked to join
ff02::1234%wm0.  This could break application #2, especially if the two
applications use different protocols.

> 
> On Linux, can your code actually receive an IP multicast packet only with
> binding to the address (i.e., without joining the group)?

Maybe, but only if some other process on the system has already joined
the group.

(Note that I omitted the group join sockopt from my example code to make
it as minimal as possible.  I can send a more complete Python script if
there is interest.)

-Richard


> 
> Best regards,
> --
> Motoyuki OHMORI <ohmori%tottori-u.ac.jp@localhost>
> 
> On Wed, Jul 23, 2014 at 19:31:18 -0400, Richard Hansen 
> <rhansen%bbn.com@localhost> wrote:
> 
>> On 2014-07-23 07:11, Christos Zoulas wrote:
>>> In article <53CF5BF8.4000402%bbn.com@localhost>, Richard Hansen  
>>> <rhansen%bbn.com@localhost> wrote:
>>>> Hi all,
>>>>
>>>> It seems to me like in6_pcbbind_addr() should have another 'else if'
>>>> condition before line 241:
>>>>
>>>>    } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
>>>>        ...
>>>>
>>>> Or am I doing something wrong?
>>>
>>> Does this work for you? (similar to in_pcbbind_addr())...
>>
>> Thanks for the patch.  I'll try it out in a bit, but before I do I have
>> some questions.  Some of these will be answered by my testing, but I
>> wanted to ask them anyway in case you already know the answer and would
>> like to update the patch:
>>
>>   * With this patch, in6_pcbind_addr() will set in6p->in6p_laddr to the
>>     multicast group address.  Will this cause an outgoing packet sent
>>     via the socket to have the source address set to the multicast
>>     address (which would violate RFC4291)?
>>
>>   * Shouldn't in6_pcbind_addr() ensure that sin6->sin6_scope_id is
>>     non-0 if the multicast address is link-local?  (or perhaps
>>     non-global?)
>>
>>   * How does sin6->sin6_scope_id affect the binding?  Suppose I have two
>>     interfaces, wm0 and wm1.  I create two sockets and bind one to
>>     ff02::101%wm0 port 123 and the other to ff02:101%wm1 port 123.
>>     Each should only receive packets that arrive on the specified
>>     interface, but with this patch I'm guessing one of the following
>>     will happen:
>>       - the second bind() will fail (the call to in6_pcblookup_port()
>>         in in6_pcbbind_port() doesn't consider sin6_scope_id, so I
>>         think NetBSD will return EADDRINUSE)
>>       - both sockets will receive packets destined to either interface
>>       - one socket will receive packets destined to both interfaces
>>         while the other socket receives nothing
>>
>>   * Should in6_pcbind_addr() reject the bind to the multicast address
>>     if the socket type is SOCK_STREAM?
>>
>> Thanks,
>> Richard
>>
>>>
>>> christos
>>>
>>> Index: in6_pcb.c
>>> ===================================================================
>>> RCS file: /cvsroot/src/sys/netinet6/in6_pcb.c,v
>>> retrieving revision 1.125
>>> diff -u -p -u -r1.125 in6_pcb.c
>>> --- in6_pcb.c       30 May 2014 01:39:03 -0000      1.125
>>> +++ in6_pcb.c       23 Jul 2014 11:10:23 -0000
>>> @@ -218,7 +218,9 @@ in6_pcbbind_addr(struct in6pcb *in6p, st
>>>     if ((error = sa6_embedscope(sin6, ip6_use_defzone)) != 0)
>>>             return (error);
>>>  
>>> -   if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
>>> +   if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
>>> +           /* always succeed */
>>> +   } else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
>>>             if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
>>>                     return (EINVAL);
>>>             if (sin6->sin6_addr.s6_addr32[3]) {



Home | Main Index | Thread Index | Old Index