ports/155706: net/quagga: ripd is broken

Eugene Grosbein eugen at rdtc.ru
Sat Mar 19 22:00:12 UTC 2011


>Number:         155706
>Category:       ports
>Synopsis:       net/quagga: ripd is broken
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Mar 19 22:00:10 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Eugene Grosbein
>Release:        FreeBSD 8.2-STABLE i386
>Organization:
RDTC JSC
>Environment:
System: FreeBSD grosbein.pp.ru 8.2-STABLE FreeBSD 8.2-STABLE #19: Fri Feb 25 23:21:16 NOVT 2011 root at grosbein.pp.ru:/usr/local/obj/usr/local/src/sys/DADV i386

>Description:
	quagga can join interface to multicast group either
	with the RFC 1724 hack or with ip_mreqn/IP_MULTICAST_IF.

	The RFC 1724 hack for interface selection has been removed
	from FreeBSD since 7.0-RELEASE (see entry 20070612 in /usr/src/UPDATIN).
	
	The port net/quagga since quagga-0.99.17_2 contains files/patch-lib-sockopt.c
	that effectively disables use of ip_mreqn. This change broke ripd
	for FreeBSD 7.0 and later.

	ripd with this change still works in 6.x where RFC 1724 hack exists.

>How-To-Repeat:

	In FreeBSD 8.2, for ngX interfaces created by net/mpd5
	ripd cannot join multicast group and complains to the log:

Can't setsockopt IP_MULTICAST_IF on fd 11 to source address 192.168.100.50 for interface ng2
can't send packet : Permission denied

	These lines repeat every 32 seconds while ripd is running.

>Fix:
	The following patch is taken from
	https://bugzilla.quagga.net/show_bug.cgi?id=420

	We need to remove our own files/patch-lib-sockopt.c
	and replace it with this one. I've tested it with ripd and ospfd,
	it works just fine for ngX and gifX interfaces.

--- lib/sockopt.c.orig	2010-04-20 21:44:26.000000000 -0400
+++ lib/sockopt.c	2010-11-03 10:55:06.000000000 -0400
@@ -221,13 +221,13 @@ setsockopt_multicast_ipv4(int sock, 
 #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
   /* This is better because it uses ifindex directly */
   struct ip_mreqn mreqn;
+  struct group_req gr;
+  struct sockaddr_in *si;
   int ret;
   
   switch (optname)
     {
     case IP_MULTICAST_IF:
-    case IP_ADD_MEMBERSHIP:
-    case IP_DROP_MEMBERSHIP:
       memset (&mreqn, 0, sizeof(mreqn));
 
       if (mcast_addr)
@@ -240,6 +240,37 @@ setsockopt_multicast_ipv4(int sock, 
       
       ret = setsockopt(sock, IPPROTO_IP, optname,
 		       (void *)&mreqn, sizeof(mreqn));
+      return ret;
+      break;
+
+    case IP_ADD_MEMBERSHIP:
+    case IP_DROP_MEMBERSHIP:
+      if (ifindex)
+        {
+          memset (&gr, 0, sizeof(gr));
+	  si = (struct sockaddr_in *)&gr.gr_group;
+	  gr.gr_interface = ifindex;
+          if (mcast_addr)
+            si->sin_family = AF_INET;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+            si->sin_len = sizeof(struct sockaddr_in);
+#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
+	    si->sin_addr.s_addr = mcast_addr;
+          if (optname == IP_ADD_MEMBERSHIP)
+            ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void *)&gr, sizeof(gr));
+          else
+            ret = setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
+        }
+      else
+        {
+          memset (&mreqn, 0, sizeof(mreqn));
+          if (mcast_addr)
+	    mreqn.imr_multiaddr.s_addr = mcast_addr;
+	  mreqn.imr_address = if_addr;
+      
+          ret = setsockopt(sock, IPPROTO_IP, optname,
+		       (void *)&mreqn, sizeof(mreqn));
+        }
       if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
         {
 	  /* see above: handle possible problem when interface comes back up */
@@ -248,12 +279,18 @@ setsockopt_multicast_ipv4(int sock, 
 		    "re-add (fd %d, ifaddr %s, mcast %s, ifindex %u)",
 		    sock,
 		    inet_ntop(AF_INET, &if_addr, buf[0], sizeof(buf[0])),
-		    inet_ntop(AF_INET, &mreqn.imr_multiaddr,
-			      buf[1], sizeof(buf[1])), ifindex);
-	  setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
-		     (void *)&mreqn, sizeof(mreqn));
-	  ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
-			   (void *)&mreqn, sizeof(mreqn));
+		    inet_ntop(AF_INET, &mcast_addr, buf[1], sizeof(buf[1])),
+                    ifindex);
+          if (ifindex)
+            {
+	      setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
+	      ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void *)&gr, sizeof(gr));
+            }
+          else
+            {
+	      setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&mreqn, sizeof(mreqn));
+	      ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreqn, sizeof(mreqn));
+            }
         }
       return ret;
       break;

>Release-Note:
>Audit-Trail:
>Unformatted:



More information about the freebsd-ports-bugs mailing list