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