Deal with multicast packets in a manner similar to Solaris, RFC 3376, and
authorMatthew Dillon <dillon@dragonflybsd.org>
Tue, 28 Oct 2003 03:51:51 +0000 (03:51 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Tue, 28 Oct 2003 03:51:51 +0000 (03:51 +0000)
draft-ietf-magma-msf-api-05.txt.   Multicast packets are not sent to
multicast-unaware sockets or to sockets not bound to the interface the
packet came in on.

The sysctl net.inet.udp.strict_mcast_mship enables the new requirements
by default.  Original operation may be recovered by setting the sysctl to 0.

There is a relatively minor scaling issue with the per-PCB membership
array scan, which is linear.  It is not a show stopper though.

Submitted by: "William A. Carrel" <william.a@carrel.org>
Reviewed by: Jeffrey Hsu <hsu@FreeBSD.org>, dillon

sys/netinet/udp_usrreq.c

index c325a36..b81ac2d 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)udp_usrreq.c        8.6 (Berkeley) 5/23/95
  * $FreeBSD: src/sys/netinet/udp_usrreq.c,v 1.64.2.18 2003/01/24 05:11:34 sam Exp $
- * $DragonFly: src/sys/netinet/udp_usrreq.c,v 1.6 2003/08/23 11:18:00 rob Exp $
+ * $DragonFly: src/sys/netinet/udp_usrreq.c,v 1.7 2003/10/28 03:51:51 dillon Exp $
  */
 
 #include "opt_ipsec.h"
@@ -103,6 +103,10 @@ static int blackhole = 0;
 SYSCTL_INT(_net_inet_udp, OID_AUTO, blackhole, CTLFLAG_RW,
        &blackhole, 0, "Do not send port unreachables for refused connects");
 
+static int     strict_mcast_mship = 1;
+SYSCTL_INT(_net_inet_udp, OID_AUTO, strict_mcast_mship, CTLFLAG_RW,
+       &strict_mcast_mship, 0, "Only send multicast to member sockets");
+
 struct inpcbhead udb;          /* from udp_var.h */
 #define        udb6    udb  /* for KAME src sync over BSD*'s */
 struct inpcbinfo udbinfo;
@@ -152,6 +156,37 @@ udp_init()
                                 ZONE_INTERRUPT, 0);
 }
 
+/*
+ * Check multicast packets to make sure they are only sent to sockets with
+ * multicast memberships for the packet's destination address and arrival
+ * interface.  Multicast packets to multicast-unaware sockets are also
+ * disallowed.
+ *
+ * Returns 0 if the packet is acceptable, -1 if it is not.
+ */
+static __inline
+int
+check_multicast_membership(struct ip *ip, struct inpcb *inp, struct mbuf *m)
+{
+       int mshipno;
+       struct ip_moptions *mopt;
+
+       if (strict_mcast_mship == 0 ||
+           !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+               return(0);
+       }
+       mopt = inp->inp_moptions;
+       if (mopt == NULL)
+               return(-1);
+       for (mshipno = 0; mshipno <= mopt->imo_num_memberships; ++mshipno) {
+               if (ip->ip_dst.s_addr == mopt->imo_membership[mshipno]->inm_addr.s_addr &&
+                   m->m_pkthdr.rcvif == mopt->imo_membership[mshipno]->inm_ifp) {
+                       return(0);
+               }
+       }
+       return(-1);
+}
+
 void
 udp_input(m, off, proto)
        struct mbuf *m;
@@ -294,6 +329,9 @@ udp_input(m, off, proto)
                                        continue;
                        }
 
+                       if (check_multicast_membership(ip, inp, m) < 0)
+                               continue;
+
                        if (last != NULL) {
                                struct mbuf *n;