When the Ovpn server receive a multicast data packet that has to be trasmitted to the peers, if its IP destination is a multicast group to which no peer is currently subscribed, the packet is dropped instead of being broadcasted. Multicast control messages (IGMP/MLD) are still broadcasted to all peers.
Signed-off-by: Marco Baffo <[email protected]> --- drivers/net/ovpn/mcast.c | 41 ++++++++++++++++++++++++++++++++++++++-- drivers/net/ovpn/mcast.h | 1 + drivers/net/ovpn/peer.c | 7 +++++-- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/net/ovpn/mcast.c b/drivers/net/ovpn/mcast.c index c90ef2b8d8b8..59b0b62afcde 100644 --- a/drivers/net/ovpn/mcast.c +++ b/drivers/net/ovpn/mcast.c @@ -358,12 +358,49 @@ bool ovpn_mcast_snoop_skb(struct ovpn_peer *peer, struct sk_buff *skb) { if (peer->ovpn->mode != OVPN_MODE_MP) return false; + if (skb->protocol == htons(ETH_P_IP)) { if (ip_hdr(skb)->protocol == IPPROTO_IGMP) return ovpn_mcast_snoop_igmp(peer, skb); } else if (skb->protocol == htons(ETH_P_IPV6)) { - if (ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) - return ovpn_mcast_snoop_mld(peer, skb); + return ovpn_mcast_snoop_mld(peer, skb); + } + + return false; +} + +/** + * ovpn_mcast_is_control - determine whether an skb is multicast control traffic + * @skb: the packet to inspect + * + * Return: true if the skb contains IGMP or MLD control traffic, + * false otherwise + */ +bool ovpn_mcast_is_control(struct sk_buff *skb) +{ + unsigned int offset; + struct icmp6hdr *ih; + + if (skb->protocol == htons(ETH_P_IP)) + return ip_hdr(skb)->protocol == IPPROTO_IGMP; + + if (skb->protocol != htons(ETH_P_IPV6)) + return false; + + if (!ovpn_mcast_mld_offset(skb, &offset)) + return false; + + if (!pskb_may_pull(skb, offset + sizeof(*ih))) + return false; + + ih = (struct icmp6hdr *)(skb_network_header(skb) + offset); + switch (ih->icmp6_type) { + case ICMPV6_MGM_QUERY: + case ICMPV6_MGM_REPORT: + case ICMPV6_MGM_REDUCTION: + case ICMPV6_MLD2_REPORT: + return true; } + return false; } diff --git a/drivers/net/ovpn/mcast.h b/drivers/net/ovpn/mcast.h index e9e14d807270..9e06e893a355 100644 --- a/drivers/net/ovpn/mcast.h +++ b/drivers/net/ovpn/mcast.h @@ -22,6 +22,7 @@ void ovpn_mcast_leave_all(struct ovpn_peer *peer); bool ovpn_peer_list_get_by_mcast_group(struct ovpn_priv *ovpn, const struct in6_addr *group_addr, struct llist_head *list); +bool ovpn_mcast_is_control(struct sk_buff *skb); bool ovpn_mcast_snoop_skb(struct ovpn_peer *peer, struct sk_buff *skb); #endif /* _NET_OVPN_MCAST_H_ */ diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index 5159a8f9dfba..a9728a157210 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -779,8 +779,10 @@ void ovpn_peer_list_get_by_dst(struct ovpn_priv *ovpn, struct sk_buff *skb, addr_type = inet_dev_addr_type(dev_net(ovpn->dev), ovpn->dev, addr4); if (addr_type == RTN_MULTICAST) { ipv6_addr_set_v4mapped(addr4, &addr6); - if (!ovpn_peer_list_get_by_mcast_group(ovpn, &addr6, list)) + if (!ovpn_peer_list_get_by_mcast_group(ovpn, &addr6, list) && + ovpn_mcast_is_control(skb)) { ovpn_peer_list_get_all(ovpn, list); + } } else if (addr_type == RTN_BROADCAST) { ovpn_peer_list_get_all(ovpn, list); } @@ -795,7 +797,8 @@ void ovpn_peer_list_get_by_dst(struct ovpn_priv *ovpn, struct sk_buff *skb, rcu_read_unlock(); if (ipv6_addr_is_multicast(&addr6) && - !ovpn_peer_list_get_by_mcast_group(ovpn, &addr6, list)) { + !ovpn_peer_list_get_by_mcast_group(ovpn, &addr6, list) && + ovpn_mcast_is_control(skb)) { ovpn_peer_list_get_all(ovpn, list); } return; -- 2.43.0 _______________________________________________ Openvpn-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openvpn-devel
