On 11.04.2018 13:02, Andre Naujoks wrote: > Hi. Hi again.
Since it has been a month now, I'd like to send a little "ping" on this subject. Is anything wrong with this? Or was it just bad timing? Regards Andre > > I was running into a problem, when trying to join multiple multicast groups > on a single socket and thus binding to the any-address on said socket. I > received traffic from multicast groups, I did not join on that socket and > was at first surprised by that. After reading some old e-mails/threads, > which came to the conclusion "It is, as it is." > (e.g https://marc.info/?l=linux-kernel&m=115815686626791&w=2), I discovered > the IPv4 socketoption IP_MULTICAST_ALL, which, when disabled, does exactly > what I would expect from a socket by default. > > I propose a socket option for IPv6, which does the same and has the same > default as the IPv4 version. My first thought was, to just apply > IP_MULTICAST_ALL to a ipv6 socket, but that would change the behavior of > current applications and would probably be a big no-no. > > Regards > Andre > > > From 473653086c05a3de839c3504885053f6254c7bc5 Mon Sep 17 00:00:00 2001 > From: Andre Naujoks <nauts...@gmail.com> > Date: Wed, 11 Apr 2018 12:38:28 +0200 > Subject: [PATCH] Add a socketoption IPV6_MULTICAST_ALL analogue to the IPV4 > version > > The socket option will be enabled by default to ensure current behaviour > is not changed. This is the same for the IPv4 version. > > A socket bound to in6addr_any and a specific port will receive all traffic > on that port. Analogue to IP_MULTICAST_ALL, disable this behaviour, if > one or more multicast groups were joined (using said socket) and only > pass on multicast traffic from groups, which were explicitly joined via > this socket. > > Without this option disabled a socket (system even) joined to multiple > multicast groups is very hard to get right. Filtering by destination > address has to take place in user space to avoid receiving multicast > traffic from other multicast groups, which might have traffic on the same > port. > > The extension of the IP_MULTICAST_ALL socketoption to just apply to ipv6, > too, is not done to avoid changing the behaviour of current applications. > > Signed-off-by: Andre Naujoks <nauts...@gmail.com> > --- > include/linux/ipv6.h | 3 ++- > include/uapi/linux/in6.h | 1 + > net/ipv6/af_inet6.c | 1 + > net/ipv6/ipv6_sockglue.c | 11 +++++++++++ > net/ipv6/mcast.c | 2 +- > 5 files changed, 16 insertions(+), 2 deletions(-) > > diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h > index 8415bf1a9776..495e834c1367 100644 > --- a/include/linux/ipv6.h > +++ b/include/linux/ipv6.h > @@ -274,7 +274,8 @@ struct ipv6_pinfo { > */ > dontfrag:1, > autoflowlabel:1, > - autoflowlabel_set:1; > + autoflowlabel_set:1, > + mc_all:1; > __u8 min_hopcount; > __u8 tclass; > __be32 rcv_flowinfo; > diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h > index ed291e55f024..71d82fe15b03 100644 > --- a/include/uapi/linux/in6.h > +++ b/include/uapi/linux/in6.h > @@ -177,6 +177,7 @@ struct in6_flowlabel_req { > #define IPV6_V6ONLY 26 > #define IPV6_JOIN_ANYCAST 27 > #define IPV6_LEAVE_ANYCAST 28 > +#define IPV6_MULTICAST_ALL 29 > > /* IPV6_MTU_DISCOVER values */ > #define IPV6_PMTUDISC_DONT 0 > diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c > index 8da0b513f188..7844cd9d2f10 100644 > --- a/net/ipv6/af_inet6.c > +++ b/net/ipv6/af_inet6.c > @@ -209,6 +209,7 @@ static int inet6_create(struct net *net, struct socket > *sock, int protocol, > np->hop_limit = -1; > np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; > np->mc_loop = 1; > + np->mc_all = 1; > np->pmtudisc = IPV6_PMTUDISC_WANT; > np->repflow = net->ipv6.sysctl.flowlabel_reflect; > sk->sk_ipv6only = net->ipv6.sysctl.bindv6only; > diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c > index 4d780c7f0130..b2bc1942a2ee 100644 > --- a/net/ipv6/ipv6_sockglue.c > +++ b/net/ipv6/ipv6_sockglue.c > @@ -664,6 +664,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int > level, int optname, > retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, > &mreq.ipv6mr_acaddr); > break; > } > + case IPV6_MULTICAST_ALL: > + if (optlen < sizeof(int)) > + goto e_inval; > + np->mc_all = valbool; > + retv = 0; > + break; > + > case MCAST_JOIN_GROUP: > case MCAST_LEAVE_GROUP: > { > @@ -1255,6 +1262,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int > level, int optname, > val = np->mcast_oif; > break; > > + case IPV6_MULTICAST_ALL: > + val = np->mc_all; > + break; > + > case IPV6_UNICAST_IF: > val = (__force int)htonl((__u32) np->ucast_oif); > break; > diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c > index 793159d77d8a..623ad00eb3c2 100644 > --- a/net/ipv6/mcast.c > +++ b/net/ipv6/mcast.c > @@ -622,7 +622,7 @@ bool inet6_mc_check(struct sock *sk, const struct > in6_addr *mc_addr, > } > if (!mc) { > rcu_read_unlock(); > - return true; > + return np->mc_all; > } > read_lock(&mc->sflock); > psl = mc->sflist; >