netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* multicast loop with include filters fix [PATCH]
@ 2004-01-23  2:02 David Stevens
  2004-01-23  1:57 ` David S. Miller
  0 siblings, 1 reply; 5+ messages in thread
From: David Stevens @ 2004-01-23  2:02 UTC (permalink / raw)
  To: davem, netdev; +Cc: stevenh


[-- Attachment #1.1: Type: text/plain, Size: 3995 bytes --]





When sending a multicast and using looping back a copy to the
local machine, the interface filter checks can be done before the
source address is specified. For an INCLUDE filter, this won't match
the allowed sources and the packets won't be delivered locally,
even when the ultimate source address chosen is in the allowed list.

The patch below fixes the filter checks for both IGMPv3 and MLDv2
to only apply when a source address is available.

Thanks to Steven Hessing for reporting the problem and providing
a test case for reproducing it.

                              +-DLS

[not-whitespace-mangled patch attached]

diff -ruN linux-2.6.2-rc1/net/ipv4/igmp.c linux-2.6.2-rc1F1/net/ipv4/igmp.c
--- linux-2.6.2-rc1/net/ipv4/igmp.c 2004-01-21 14:03:35.000000000 -0800
+++ linux-2.6.2-rc1F1/net/ipv4/igmp.c     2004-01-22 17:11:38.000000000 -0800
@@ -2084,16 +2084,19 @@
      if (im && proto == IPPROTO_IGMP) {
            rv = 1;
      } else if (im) {
-           for (psf=im->sources; psf; psf=psf->sf_next) {
-                 if (psf->sf_inaddr == src_addr)
-                       break;
-           }
-           if (psf)
-                 rv = psf->sf_count[MCAST_INCLUDE] ||
-                       psf->sf_count[MCAST_EXCLUDE] !=
-                       im->sfcount[MCAST_EXCLUDE];
-           else
-                 rv = im->sfcount[MCAST_EXCLUDE] != 0;
+           if (src_addr) {
+                 for (psf=im->sources; psf; psf=psf->sf_next) {
+                       if (psf->sf_inaddr == src_addr)
+                             break;
+                 }
+                 if (psf)
+                       rv = psf->sf_count[MCAST_INCLUDE] ||
+                             psf->sf_count[MCAST_EXCLUDE] !=
+                             im->sfcount[MCAST_EXCLUDE];
+                 else
+                       rv = im->sfcount[MCAST_EXCLUDE] != 0;
+           } else
+                 rv = 1; /* unspecified source; tentatively allow */
      }
      read_unlock(&in_dev->lock);
      return rv;
diff -ruN linux-2.6.2-rc1/net/ipv6/mcast.c linux-2.6.2-rc1F1/net/ipv6/mcast.c
--- linux-2.6.2-rc1/net/ipv6/mcast.c      2004-01-21 14:03:35.000000000 -0800
+++ linux-2.6.2-rc1F1/net/ipv6/mcast.c    2004-01-22 17:29:29.000000000 -0800
@@ -918,20 +918,24 @@
                        break;
            }
            if (mc) {
-                 struct ip6_sf_list *psf;
+                 if (ipv6_addr_any(src_addr)) {
+                       struct ip6_sf_list *psf;

-                 spin_lock_bh(&mc->mca_lock);
-                 for (psf=mc->mca_sources; psf; psf=psf->sf_next) {
-                       if (ipv6_addr_cmp(&psf->sf_addr, src_addr) == 0)
-                             break;
-                 }
-                 if (psf)
-                       rv = psf->sf_count[MCAST_INCLUDE] ||
-                             psf->sf_count[MCAST_EXCLUDE] !=
-                             mc->mca_sfcount[MCAST_EXCLUDE];
-                 else
-                       rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0;
-                 spin_unlock_bh(&mc->mca_lock);
+                       spin_lock_bh(&mc->mca_lock);
+                       for (psf=mc->mca_sources;psf;psf=psf->sf_next) {
+                             if (ipv6_addr_cmp(&psf->sf_addr,
+                                 src_addr) == 0)
+                                   break;
+                       }
+                       if (psf)
+                             rv = psf->sf_count[MCAST_INCLUDE] ||
+                                   psf->sf_count[MCAST_EXCLUDE] !=
+                                   mc->mca_sfcount[MCAST_EXCLUDE];
+                       else
+                             rv = mc->mca_sfcount[MCAST_EXCLUDE] !=0;
+                       spin_unlock_bh(&mc->mca_lock);
+                 } else
+                       rv = 1; /* don't filter unspecified source */
            }
            read_unlock_bh(&idev->lock);
            in6_dev_put(idev);

(See attached file: igmpf1.patch)

[-- Attachment #1.2: Type: text/html, Size: 3469 bytes --]

[-- Attachment #2: igmpf1.patch --]
[-- Type: application/octet-stream, Size: 2287 bytes --]

diff -ruN linux-2.6.2-rc1/net/ipv4/igmp.c linux-2.6.2-rc1F1/net/ipv4/igmp.c
--- linux-2.6.2-rc1/net/ipv4/igmp.c	2004-01-21 14:03:35.000000000 -0800
+++ linux-2.6.2-rc1F1/net/ipv4/igmp.c	2004-01-22 17:11:38.000000000 -0800
@@ -2084,16 +2084,19 @@
 	if (im && proto == IPPROTO_IGMP) {
 		rv = 1;
 	} else if (im) {
-		for (psf=im->sources; psf; psf=psf->sf_next) {
-			if (psf->sf_inaddr == src_addr)
-				break;
-		}
-		if (psf)
-			rv = psf->sf_count[MCAST_INCLUDE] ||
-				psf->sf_count[MCAST_EXCLUDE] !=
-				im->sfcount[MCAST_EXCLUDE];
-		else
-			rv = im->sfcount[MCAST_EXCLUDE] != 0;
+		if (src_addr) {
+			for (psf=im->sources; psf; psf=psf->sf_next) {
+				if (psf->sf_inaddr == src_addr)
+					break;
+			}
+			if (psf)
+				rv = psf->sf_count[MCAST_INCLUDE] ||
+					psf->sf_count[MCAST_EXCLUDE] !=
+					im->sfcount[MCAST_EXCLUDE];
+			else
+				rv = im->sfcount[MCAST_EXCLUDE] != 0;
+		} else
+			rv = 1; /* unspecified source; tentatively allow */
 	}
 	read_unlock(&in_dev->lock);
 	return rv;
diff -ruN linux-2.6.2-rc1/net/ipv6/mcast.c linux-2.6.2-rc1F1/net/ipv6/mcast.c
--- linux-2.6.2-rc1/net/ipv6/mcast.c	2004-01-21 14:03:35.000000000 -0800
+++ linux-2.6.2-rc1F1/net/ipv6/mcast.c	2004-01-22 17:29:29.000000000 -0800
@@ -918,20 +918,24 @@
 				break;
 		}
 		if (mc) {
-			struct ip6_sf_list *psf;
+			if (ipv6_addr_any(src_addr)) {
+				struct ip6_sf_list *psf;
 
-			spin_lock_bh(&mc->mca_lock);
-			for (psf=mc->mca_sources; psf; psf=psf->sf_next) {
-				if (ipv6_addr_cmp(&psf->sf_addr, src_addr) == 0)
-					break;
-			}
-			if (psf)
-				rv = psf->sf_count[MCAST_INCLUDE] ||
-					psf->sf_count[MCAST_EXCLUDE] !=
-					mc->mca_sfcount[MCAST_EXCLUDE];
-			else
-				rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0;
-			spin_unlock_bh(&mc->mca_lock);
+				spin_lock_bh(&mc->mca_lock);
+				for (psf=mc->mca_sources;psf;psf=psf->sf_next) {
+					if (ipv6_addr_cmp(&psf->sf_addr,
+					    src_addr) == 0)
+						break;
+				}
+				if (psf)
+					rv = psf->sf_count[MCAST_INCLUDE] ||
+						psf->sf_count[MCAST_EXCLUDE] !=
+						mc->mca_sfcount[MCAST_EXCLUDE];
+				else
+					rv = mc->mca_sfcount[MCAST_EXCLUDE] !=0;
+				spin_unlock_bh(&mc->mca_lock);
+			} else
+				rv = 1; /* don't filter unspecified source */
 		}
 		read_unlock_bh(&idev->lock);
 		in6_dev_put(idev);

^ permalink raw reply	[flat|nested] 5+ messages in thread
* Re: multicast loop with include filters fix [PATCH]
@ 2004-01-23 20:27 David Stevens
  0 siblings, 0 replies; 5+ messages in thread
From: David Stevens @ 2004-01-23 20:27 UTC (permalink / raw)
  To: davem; +Cc: netdev, stevenh


[-- Attachment #1.1: Type: text/plain, Size: 673 bytes --]





Dave,
      I had a stupid typo in the v6 side of this patch, which
reverses the sense of the check; here's a patch to fix the patch.
Sorry about that.

                        +-DLS

--- linux-2.6.2-rc1F1/net/ipv6/mcast.c.orig     2004-01-23 12:10:55.615139688 -0800
+++ linux-2.6.2-rc1F1/net/ipv6/mcast.c    2004-01-23 12:11:15.477120208 -0800
@@ -918,7 +918,7 @@
                        break;
            }
            if (mc) {
-                 if (ipv6_addr_any(src_addr)) {
+                 if (!ipv6_addr_any(src_addr)) {
                        struct ip6_sf_list *psf;

                        spin_lock_bh(&mc->mca_lock);

(See attached file: mldfix.patch)

[-- Attachment #1.2: Type: text/html, Size: 661 bytes --]

[-- Attachment #2: mldfix.patch --]
[-- Type: application/octet-stream, Size: 342 bytes --]

--- linux-2.6.2-rc1F1/net/ipv6/mcast.c.orig	2004-01-23 12:10:55.615139688 -0800
+++ linux-2.6.2-rc1F1/net/ipv6/mcast.c	2004-01-23 12:11:15.477120208 -0800
@@ -918,7 +918,7 @@
 				break;
 		}
 		if (mc) {
-			if (ipv6_addr_any(src_addr)) {
+			if (!ipv6_addr_any(src_addr)) {
 				struct ip6_sf_list *psf;
 
 				spin_lock_bh(&mc->mca_lock);

^ permalink raw reply	[flat|nested] 5+ messages in thread
* Re: multicast loop with include filters fix [PATCH]
@ 2004-01-23 22:39 David Stevens
  2004-01-24 18:00 ` David S. Miller
  0 siblings, 1 reply; 5+ messages in thread
From: David Stevens @ 2004-01-23 22:39 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, stevenh


[-- Attachment #1.1: Type: text/plain, Size: 3426 bytes --]





Dave,
      Here's the 2.4.x version of the patch.

                        +-DLS

diff -ruN linux-2.4.25-pre7/net/ipv4/igmp.c linux-2.4.25-pre7F1/net/ipv4/igmp.c
--- linux-2.4.25-pre7/net/ipv4/igmp.c     2004-01-23 13:54:35.000000000 -0800
+++ linux-2.4.25-pre7F1/net/ipv4/igmp.c   2004-01-23 13:58:43.000000000 -0800
@@ -2071,16 +2071,19 @@
       * Differs from 2.5.x here.   +-DLS 4/23/03
       */
      if (im) {
-           for (psf=im->sources; psf; psf=psf->sf_next) {
-                 if (psf->sf_inaddr == src_addr)
-                       break;
-           }
-           if (psf)
-                 rv = psf->sf_count[MCAST_INCLUDE] ||
-                       psf->sf_count[MCAST_EXCLUDE] !=
-                       im->sfcount[MCAST_EXCLUDE];
-           else
-                 rv = im->sfcount[MCAST_EXCLUDE] != 0;
+           if (src_addr) {
+                 for (psf=im->sources; psf; psf=psf->sf_next) {
+                       if (psf->sf_inaddr == src_addr)
+                             break;
+                 }
+                 if (psf)
+                       rv = psf->sf_count[MCAST_INCLUDE] ||
+                             psf->sf_count[MCAST_EXCLUDE] !=
+                             im->sfcount[MCAST_EXCLUDE];
+                 else
+                       rv = im->sfcount[MCAST_EXCLUDE] != 0;
+           } else
+                 rv = 1;
      }
      read_unlock(&in_dev->lock);
      return rv;
diff -ruN linux-2.4.25-pre7/net/ipv6/mcast.c linux-2.4.25-pre7F1/net/ipv6/mcast.c
--- linux-2.4.25-pre7/net/ipv6/mcast.c    2004-01-23 13:54:35.000000000 -0800
+++ linux-2.4.25-pre7F1/net/ipv6/mcast.c  2004-01-23 13:56:19.000000000 -0800
@@ -914,20 +914,24 @@
                        break;
            }
            if (mc) {
-                 struct ip6_sf_list *psf;
+                 if (!ipv6_addr_any(src_addr)) {
+                       struct ip6_sf_list *psf;

-                 spin_lock_bh(&mc->mca_lock);
-                 for (psf=mc->mca_sources; psf; psf=psf->sf_next) {
-                       if (ipv6_addr_cmp(&psf->sf_addr, src_addr) == 0)
-                             break;
-                 }
-                 if (psf)
-                       rv = psf->sf_count[MCAST_INCLUDE] ||
-                             psf->sf_count[MCAST_EXCLUDE] !=
-                             mc->mca_sfcount[MCAST_EXCLUDE];
-                 else
-                       rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0;
-                 spin_unlock_bh(&mc->mca_lock);
+                       spin_lock_bh(&mc->mca_lock);
+                       for (psf=mc->mca_sources;psf;psf=psf->sf_next) {
+                             if (ipv6_addr_cmp(&psf->sf_addr,
+                                 src_addr) == 0)
+                                   break;
+                       }
+                       if (psf)
+                             rv = psf->sf_count[MCAST_INCLUDE] ||
+                                   psf->sf_count[MCAST_EXCLUDE] !=
+                                   mc->mca_sfcount[MCAST_EXCLUDE];
+                       else
+                             rv = mc->mca_sfcount[MCAST_EXCLUDE] !=0;
+                       spin_unlock_bh(&mc->mca_lock);
+                 } else
+                       rv = 1; /* don't filter unspecified source */
            }
            read_unlock_bh(&idev->lock);
            in6_dev_put(idev);

(See attached file: 2.4.25-pre7IGMP.patch)

[-- Attachment #1.2: Type: text/html, Size: 2853 bytes --]

[-- Attachment #2: 2.4.25-pre7IGMP.patch --]
[-- Type: application/octet-stream, Size: 2255 bytes --]

diff -ruN linux-2.4.25-pre7/net/ipv4/igmp.c linux-2.4.25-pre7F1/net/ipv4/igmp.c
--- linux-2.4.25-pre7/net/ipv4/igmp.c	2004-01-23 13:54:35.000000000 -0800
+++ linux-2.4.25-pre7F1/net/ipv4/igmp.c	2004-01-23 13:58:43.000000000 -0800
@@ -2071,16 +2071,19 @@
 	 * Differs from 2.5.x here.	+-DLS 4/23/03
 	 */
 	if (im) {
-		for (psf=im->sources; psf; psf=psf->sf_next) {
-			if (psf->sf_inaddr == src_addr)
-				break;
-		}
-		if (psf)
-			rv = psf->sf_count[MCAST_INCLUDE] ||
-				psf->sf_count[MCAST_EXCLUDE] !=
-				im->sfcount[MCAST_EXCLUDE];
-		else
-			rv = im->sfcount[MCAST_EXCLUDE] != 0;
+		if (src_addr) {
+			for (psf=im->sources; psf; psf=psf->sf_next) {
+				if (psf->sf_inaddr == src_addr)
+					break;
+			}
+			if (psf)
+				rv = psf->sf_count[MCAST_INCLUDE] ||
+					psf->sf_count[MCAST_EXCLUDE] !=
+					im->sfcount[MCAST_EXCLUDE];
+			else
+				rv = im->sfcount[MCAST_EXCLUDE] != 0;
+		} else
+			rv = 1;
 	}
 	read_unlock(&in_dev->lock);
 	return rv;
diff -ruN linux-2.4.25-pre7/net/ipv6/mcast.c linux-2.4.25-pre7F1/net/ipv6/mcast.c
--- linux-2.4.25-pre7/net/ipv6/mcast.c	2004-01-23 13:54:35.000000000 -0800
+++ linux-2.4.25-pre7F1/net/ipv6/mcast.c	2004-01-23 13:56:19.000000000 -0800
@@ -914,20 +914,24 @@
 				break;
 		}
 		if (mc) {
-			struct ip6_sf_list *psf;
+			if (!ipv6_addr_any(src_addr)) {
+				struct ip6_sf_list *psf;
 
-			spin_lock_bh(&mc->mca_lock);
-			for (psf=mc->mca_sources; psf; psf=psf->sf_next) {
-				if (ipv6_addr_cmp(&psf->sf_addr, src_addr) == 0)
-					break;
-			}
-			if (psf)
-				rv = psf->sf_count[MCAST_INCLUDE] ||
-					psf->sf_count[MCAST_EXCLUDE] !=
-					mc->mca_sfcount[MCAST_EXCLUDE];
-			else
-				rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0;
-			spin_unlock_bh(&mc->mca_lock);
+				spin_lock_bh(&mc->mca_lock);
+				for (psf=mc->mca_sources;psf;psf=psf->sf_next) {
+					if (ipv6_addr_cmp(&psf->sf_addr,
+					    src_addr) == 0)
+						break;
+				}
+				if (psf)
+					rv = psf->sf_count[MCAST_INCLUDE] ||
+						psf->sf_count[MCAST_EXCLUDE] !=
+						mc->mca_sfcount[MCAST_EXCLUDE];
+				else
+					rv = mc->mca_sfcount[MCAST_EXCLUDE] !=0;
+				spin_unlock_bh(&mc->mca_lock);
+			} else
+				rv = 1; /* don't filter unspecified source */
 		}
 		read_unlock_bh(&idev->lock);
 		in6_dev_put(idev);

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2004-01-24 18:00 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-01-23  2:02 multicast loop with include filters fix [PATCH] David Stevens
2004-01-23  1:57 ` David S. Miller
  -- strict thread matches above, loose matches on Subject: below --
2004-01-23 20:27 David Stevens
2004-01-23 22:39 David Stevens
2004-01-24 18:00 ` David S. Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).