aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbms <bms@FreeBSD.org>2009-03-18 23:18:53 +0800
committerbms <bms@FreeBSD.org>2009-03-18 23:18:53 +0800
commitc54435fc9cd854b301a2be5b3583de85171da9a7 (patch)
tree5ad038625dd4e1b46a53e779c94a14f8ad09b1fa
parent2305085469194f14eed786a942b9497ed04ddab2 (diff)
downloadfreebsd-ports-gnome-c54435fc9cd854b301a2be5b3583de85171da9a7.tar.gz
freebsd-ports-gnome-c54435fc9cd854b301a2be5b3583de85171da9a7.tar.zst
freebsd-ports-gnome-c54435fc9cd854b301a2be5b3583de85171da9a7.zip
Add new port igmpproxy.
This is an IGMPv2 aware multicast forwarding proxy. It cannot be run simultaneously with other multicast routing daemons. PR: ports/130174 Submitted by: Alexander Chernikov
-rw-r--r--net/Makefile1
-rw-r--r--net/igmpproxy/Makefile41
-rw-r--r--net/igmpproxy/distinfo3
-rw-r--r--net/igmpproxy/files/igmpproxy.in23
-rw-r--r--net/igmpproxy/files/patch-freebsd1082
-rw-r--r--net/igmpproxy/pkg-descr5
6 files changed, 1155 insertions, 0 deletions
diff --git a/net/Makefile b/net/Makefile
index f9e8d3875e24..67eced086f6d 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -219,6 +219,7 @@
SUBDIR += iffinder
SUBDIR += ifstat
SUBDIR += ifstated
+ SUBDIR += igmpproxy
SUBDIR += ilbc
SUBDIR += imapproxy
SUBDIR += iodine
diff --git a/net/igmpproxy/Makefile b/net/igmpproxy/Makefile
new file mode 100644
index 000000000000..d42f034eb5bc
--- /dev/null
+++ b/net/igmpproxy/Makefile
@@ -0,0 +1,41 @@
+# New ports collection makefile for: igmpproxy
+# Date created: 5 January 2009
+# Whom: asami
+#
+# $FreeBSD$
+#
+
+PORTNAME= igmpproxy
+PORTVERSION= 0.1
+CATEGORIES= net
+MASTER_SITES= ${MASTER_SITE_SOURCEFORGE}
+MASTER_SITE_SUBDIR= ${PORTNAME}
+DISTNAME= ${PORTNAME}-src-${PORTVERSION}-beta2
+
+MAINTAINER= melifaro@ipfw.ru
+COMMENT= Multicast forwarding IGMP proxy
+
+HOMEPAGE= http://igmpproxy.sourceforge.net/
+
+WRKSRC= ${WRKDIR}/${PORTNAME}-${PORTVERSION}
+BUILD_WRKSRC= ${WRKSRC}/src
+
+USE_RC_SUBR= igmpproxy
+USE_GMAKE= yes
+
+MAN5= igmpproxy.conf.5
+MAN8= igmpproxy.8
+
+PLIST_FILES= sbin/igmpproxy \
+ etc/igmpproxy.conf.sample
+
+post-extract:
+ @${MV} ${WRKDIR}/${PORTNAME} ${WRKDIR}/${PORTNAME}-${PORTVERSION}
+
+do-install:
+ @${INSTALL_PROGRAM} ${WRKSRC}/src/igmpproxy ${PREFIX}/sbin/
+ @${INSTALL_DATA} ${WRKSRC}/src/igmpproxy.conf ${PREFIX}/etc/igmpproxy.conf.sample
+ @${INSTALL_MAN} ${WRKSRC}/doc/igmpproxy.8 ${PREFIX}/man/man8/
+ @${INSTALL_MAN} ${WRKSRC}/doc/igmpproxy.conf.5 ${PREFIX}/man/man5/
+
+.include <bsd.port.mk>
diff --git a/net/igmpproxy/distinfo b/net/igmpproxy/distinfo
new file mode 100644
index 000000000000..7fd970c4ddc5
--- /dev/null
+++ b/net/igmpproxy/distinfo
@@ -0,0 +1,3 @@
+MD5 (igmpproxy-src-0.1-beta2.tar.gz) = 2a5a59480f44d4b14077a6b5319e9940
+SHA256 (igmpproxy-src-0.1-beta2.tar.gz) = 7f6e5486e84827150c8ca402967c96334bbd62b9f785195c4ee84da1218abb40
+SIZE (igmpproxy-src-0.1-beta2.tar.gz) = 35103
diff --git a/net/igmpproxy/files/igmpproxy.in b/net/igmpproxy/files/igmpproxy.in
new file mode 100644
index 000000000000..d579251515f2
--- /dev/null
+++ b/net/igmpproxy/files/igmpproxy.in
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: igmpproxy
+# REQUIRE: NETWORKING
+
+# The following variables are provided to control startup of igmpproxy
+# rc configuration file (eg /etc/rc.conf):
+# igmpproxy_enable (bool): Set to "NO" by default.
+# Set it to "YES" to enable igmpproxy.
+
+. %%RC_SUBR%%
+
+name="igmpproxy"
+rcvar=`set_rcvar`
+command="%%PREFIX%%/sbin/${name}"
+required_files="%%PREFIX%%/etc/igmpproxy.conf"
+igmpproxy_enable=${igmpproxy_enable-"NO"}
+
+load_rc_config $name
+run_rc_command "$1"
diff --git a/net/igmpproxy/files/patch-freebsd b/net/igmpproxy/files/patch-freebsd
new file mode 100644
index 000000000000..6bb62483f09e
--- /dev/null
+++ b/net/igmpproxy/files/patch-freebsd
@@ -0,0 +1,1082 @@
+--- src/Makefile.orig 2005-08-20 13:34:18.000000000 +0100
++++ src/Makefile 2009-03-18 14:39:19.000000000 +0000
+@@ -1,12 +1,12 @@
+
+ #BINDIR=../bin
+ BINDIR=/usr/local/bin
+-ETCDIR=/etc
+-MANDIR=/usr/share/man
++ETCDIR=/usr/local/etc
++MANDIR=/usr/local/man
+
+
+ # CFLAGS=-g
+-CFLAGS=-O
++CFLAGS+=-O2 -Wall -Wextra -fno-builtin-log
+
+ default : build.h igmpproxy
+
+@@ -21,8 +21,11 @@
+ cp ../doc/igmpproxy.conf.5 ${MANDIR}/man5
+ if [ ! -e ${ETCDIR}/igmpproxy.conf ]; then cp igmpproxy.conf ${ETCDIR}; fi
+
+-igmpproxy : igmpproxy.o config.o confread.o request.o udpsock.o mcgroup.o rttable.o \
+- igmp.o ifvc.o callout.o kern.o syslog.o lib.o mroute-api.o
++SRC = igmpproxy.c config.c confread.c request.c mcgroup.c rttable.c \
++ igmp.c ifvc.c callout.c kern.c syslog.c lib.c mroute-api.c
++OBJS = ${SRC:.c=.o}
++igmpproxy: build.h ${OBJS}
++ $(CC) ${CFLAGS} ${OBJS} -o igmpproxy
+
+ build.h :
+ echo '#define BUILD "' `date +%y%m%d` '"' >build.h
+--- src/config.c.orig 2005-05-24 16:49:29.000000000 +0100
++++ src/config.c 2009-03-18 14:35:31.000000000 +0000
+@@ -177,7 +177,7 @@
+ }
+
+ // Loop through all VIFs...
+- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) {
++ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) {
+ if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) {
+
+ // Now try to find a matching config...
+@@ -255,7 +255,7 @@
+ while(token != NULL) {
+ if(strcmp("altnet", token)==0) {
+ // Altnet...
+- struct in_addr networkAddr;
++ //struct in_addr networkAddr;
+
+ token = nextConfigToken();
+ IF_DEBUG log(LOG_DEBUG, 0, "Config: IF: Got altnet token %s.",token);
+@@ -347,7 +347,7 @@
+ mask <<= (32 - bitcnt);
+ }
+
+- if(addr == -1 || addr == 0) {
++ if(addr == (uint32) -1 || addr == 0) {
+ log(LOG_WARNING, 0, "Unable to parse address token '%s'.", addrstr);
+ return NULL;
+ }
+--- src/defs.h.orig 2005-08-20 13:44:47.000000000 +0100
++++ src/defs.h 2009-03-18 14:35:31.000000000 +0000
+@@ -40,10 +40,18 @@
+ #include <stdlib.h>
+ #include <syslog.h>
+ #include <signal.h>
+-
+ #include <sys/socket.h>
++
++#ifdef __FreeBSD__
++#include <string.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <sys/ioctl.h>
++
++#else
+ #include <sys/un.h>
+ #include <sys/time.h>
++#endif
+
+ #include <net/if.h>
+
+@@ -52,15 +60,25 @@
+ #include <linux/in.h>
+ #include <linux/mroute.h>
+ #else
++#ifdef __FreeBSD__
++ #include <alias.h>
++ #include <net/route.h>
+ #include <netinet/in.h>
++ #include <netinet/ip_mroute.h>
++#endif
++ #include <netinet/in.h>
++ #include <netinet/in_systm.h>
+ #include <netinet/ip.h>
+ #include <netinet/igmp.h>
+ #include <arpa/inet.h>
+ #endif
+
+-
+ // The default path for the config file...
++#ifdef __FreeBSD__
++#define IGMPPROXY_CONFIG_FILEPATH "/usr/local/etc/igmpproxy.conf"
++#else
+ #define IGMPPROXY_CONFIG_FILEPATH "/etc/igmpproxy.conf"
++#endif
+ #define ENABLE_DEBUG 1
+
+ /*
+@@ -72,9 +90,31 @@
+
+ #define MAX_MC_VIFS 32 // !!! check this const in the specific includes
+
++#ifndef IGMP_MEMBERSHIP_QUERY
++#define IGMP_MEMBERSHIP_QUERY IGMP_HOST_MEMBERSHIP_QUERY
++#endif
++#ifndef IGMP_V1_MEMBERSHIP_REPORT
++#define IGMP_V1_MEMBERSHIP_REPORT IGMP_v1_HOST_MEMBERSHIP_REPORT
++#endif
++#ifndef IGMP_V2_MEMBERSHIP_REPORT
++#define IGMP_V2_MEMBERSHIP_REPORT IGMP_v2_HOST_MEMBERSHIP_REPORT
++#endif
++#ifndef IGMP_V2_LEAVE_GROUP
++#define IGMP_V2_LEAVE_GROUP IGMP_HOST_LEAVE_MESSAGE
++#endif
++
++#ifndef INADDR_ALLRTRS_GROUP
++/* address for multicast mtrace msg */
++#define INADDR_ALLRTRS_GROUP (u_int32_t)0xe0000002 /* 224.0.0.2 */
++#endif
++
+ // Useful macros..
++#ifndef MIN
+ #define MIN( a, b ) ((a) < (b) ? (a) : (b))
++#endif
++#ifndef MAX
+ #define MAX( a, b ) ((a) < (b) ? (b) : (a))
++#endif
+ #define VCMC( Vc ) (sizeof( Vc ) / sizeof( (Vc)[ 0 ] ))
+ #define VCEP( Vc ) (&(Vc)[ VCMC( Vc ) ])
+
+@@ -126,7 +166,12 @@
+
+ #define IF_DEBUG if(Log2Stderr & LOG_DEBUG)
+
+-void log( int Serverity, int Errno, const char *FmtSt, ... );
++#ifdef DEVEL_LOGGING
++#define log(Severity, Errno, Fmt, args...) _log((Severity), (Errno), __FUNCTION__, __LINE__, (Fmt), ##args)
++void _log( int Serverity, int Errno, const char *func, int line, const char *FmtSt, ...);
++#else
++void log( int Serverity, int Errno, const char *FmtSt, ...);
++#endif
+
+ /* ifvc.c
+ */
+@@ -196,6 +241,7 @@
+ struct IfDesc *getIfByName( const char *IfName );
+ struct IfDesc *getIfByIx( unsigned Ix );
+ struct IfDesc *getIfByAddress( uint32 Ix );
++int isAdressValidForIf( struct IfDesc* intrface, uint32 ipaddr );
+
+ /* mroute-api.c
+ */
+@@ -235,7 +281,7 @@
+ char *fmtInAdr( char *St, struct in_addr InAdr );
+ char *inetFmt(uint32 addr, char *s);
+ char *inetFmts(uint32 addr, uint32 mask, char *s);
+-int inetCksum(u_short *addr, u_int len);
++int inetChksum(u_short *addr, u_int len);
+
+ /* kern.c
+ */
+@@ -264,7 +310,7 @@
+ void initRouteTable();
+ void clearAllRoutes();
+ int insertRoute(uint32 group, int ifx);
+-int activateRoute(uint32 group, uint32 originAddr);
++int activateRoute(uint32 group, uint32 originAddr, int downIf);
+ void ageActiveRoutes();
+ void setRouteLastMemberMode(uint32 group);
+ int lastMemberGroupAge(uint32 group);
+--- src/ifvc.c.orig 2005-05-24 16:49:18.000000000 +0100
++++ src/ifvc.c 2009-03-18 14:35:31.000000000 +0000
+@@ -32,7 +32,11 @@
+ */
+
+ #include "defs.h"
++#ifdef __FreeBSD__
++#include <ifaddrs.h>
++#else
+ #include <linux/sockios.h>
++#endif
+
+ struct IfDesc IfDescVc[ MAX_IF ], *IfDescEp = IfDescVc;
+
+@@ -42,119 +46,91 @@
+ **
+ */
+ void buildIfVc() {
+- struct ifreq IfVc[ sizeof( IfDescVc ) / sizeof( IfDescVc[ 0 ] ) ];
+- struct ifreq *IfEp;
++ struct ifaddrs *ifap, *ifa;
++ struct IfDesc *ifp;
++ struct SubnetList *net;
+
+- int Sock;
+-
+- if ( (Sock = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 )
+- log( LOG_ERR, errno, "RAW socket open" );
+-
+- /* get If vector
+- */
+- {
+- struct ifconf IoCtlReq;
+-
+- IoCtlReq.ifc_buf = (void *)IfVc;
+- IoCtlReq.ifc_len = sizeof( IfVc );
+-
+- if ( ioctl( Sock, SIOCGIFCONF, &IoCtlReq ) < 0 )
+- log( LOG_ERR, errno, "ioctl SIOCGIFCONF" );
+-
+- IfEp = (void *)((char *)IfVc + IoCtlReq.ifc_len);
+- }
++ if (getifaddrs(&ifap) < 0)
++ log( LOG_ERR, errno, "getifaddrs" );
+
+ /* loop over interfaces and copy interface info to IfDescVc
+ */
+ {
+- struct ifreq *IfPt;
+- struct IfDesc *IfDp;
+-
+ // Temp keepers of interface params...
+ uint32 addr, subnet, mask;
+
+- for ( IfPt = IfVc; IfPt < IfEp; IfPt++ ) {
+- struct ifreq IfReq;
++ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ char FmtBu[ 32 ];
+
+- strncpy( IfDescEp->Name, IfPt->ifr_name, sizeof( IfDescEp->Name ) );
+-
+- // Currently don't set any allowed nets...
+- //IfDescEp->allowednets = NULL;
+-
+- // Set the index to -1 by default.
+- IfDescEp->index = -1;
++ if (IfDescEp >= &IfDescVc[ MAX_IF ]) {
++ log(LOG_WARNING, 0, "Too many interfaces, skipping %d", ifa->ifa_name);
++ continue;
++ }
+
+- /* don't retrieve more info for non-IP interfaces
++ /* ignore non-IP interfaces
+ */
+- if ( IfPt->ifr_addr.sa_family != AF_INET ) {
+- IfDescEp->InAdr.s_addr = 0; /* mark as non-IP interface */
+- IfDescEp++;
++ if ( ifa->ifa_addr->sa_family != AF_INET )
+ continue;
+- }
+-
+- // Get the interface adress...
+- IfDescEp->InAdr = ((struct sockaddr_in *)&IfPt->ifr_addr)->sin_addr;
+- addr = IfDescEp->InAdr.s_addr;
+-
+- memcpy( IfReq.ifr_name, IfDescEp->Name, sizeof( IfReq.ifr_name ) );
+-
+- // Get the subnet mask...
+- if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0)
+- log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name);
+- mask = ((struct sockaddr_in *)&IfReq.ifr_addr)->sin_addr.s_addr;
+- subnet = addr & mask;
+
+- // Get the physical index of the Interface
+- if (ioctl(Sock, SIOCGIFINDEX, &IfReq ) < 0)
+- log(LOG_ERR, errno, "ioctl SIOCGIFINDEX for %s", IfReq.ifr_name);
+-
+- log(LOG_DEBUG, 0, "Physical Index value of IF '%s' is %d",
+- IfDescEp->Name, IfReq.ifr_ifindex);
++ if ((ifp = getIfByName(ifa->ifa_name)) == NULL) {
+
++ strlcpy( IfDescEp->Name, ifa->ifa_name, sizeof( IfDescEp->Name ) );
+
+- /* get if flags
+- **
+- ** typical flags:
+- ** lo 0x0049 -> Running, Loopback, Up
+- ** ethx 0x1043 -> Multicast, Running, Broadcast, Up
+- ** ipppx 0x0091 -> NoArp, PointToPoint, Up
+- ** grex 0x00C1 -> NoArp, Running, Up
+- ** ipipx 0x00C1 -> NoArp, Running, Up
+- */
+- if ( ioctl( Sock, SIOCGIFFLAGS, &IfReq ) < 0 )
+- log( LOG_ERR, errno, "ioctl SIOCGIFFLAGS" );
++ log(LOG_DEBUG, 0, "Adding Physical Index value of IF '%s' is %d",
++ IfDescEp->Name, if_nametoindex(IfDescEp->Name));
+
+- IfDescEp->Flags = IfReq.ifr_flags;
++ // Set the index to -1 by default.
++ IfDescEp->index = -1;
++
++ // Get the interface adress...
++ IfDescEp->InAdr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
++
++ /* get if flags
++ **
++ ** typical flags:
++ ** lo 0x0049 -> Running, Loopback, Up
++ ** ethx 0x1043 -> Multicast, Running, Broadcast, Up
++ ** ipppx 0x0091 -> NoArp, PointToPoint, Up
++ ** grex 0x00C1 -> NoArp, Running, Up
++ ** ipipx 0x00C1 -> NoArp, Running, Up
++ */
++
++ IfDescEp->Flags = ifa->ifa_flags;
++
++ // Set the default params for the IF...
++ IfDescEp->state = IF_STATE_DOWNSTREAM;
++ IfDescEp->robustness = DEFAULT_ROBUSTNESS;
++ IfDescEp->threshold = DEFAULT_THRESHOLD; /* ttl limit */
++ IfDescEp->ratelimit = DEFAULT_RATELIMIT;
++ IfDescEp->allowednets = NULL;
++ ifp = IfDescEp++;
++ }
+
+ // Insert the verified subnet as an allowed net...
+- IfDescEp->allowednets = (struct SubnetList *)malloc(sizeof(struct SubnetList));
+- if(IfDescEp->allowednets == NULL) log(LOG_ERR, 0, "Out of memory !");
++ addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
++ mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr;
++ subnet = addr & mask;
++
++ net = (struct SubnetList *)malloc(sizeof(struct SubnetList));
++ if(net == NULL) log(LOG_ERR, 0, "Out of memory !");
+
+ // Create the network address for the IF..
+- IfDescEp->allowednets->next = NULL;
+- IfDescEp->allowednets->subnet_mask = mask;
+- IfDescEp->allowednets->subnet_addr = subnet;
+-
+- // Set the default params for the IF...
+- IfDescEp->state = IF_STATE_DOWNSTREAM;
+- IfDescEp->robustness = DEFAULT_ROBUSTNESS;
+- IfDescEp->threshold = DEFAULT_THRESHOLD; /* ttl limit */
+- IfDescEp->ratelimit = DEFAULT_RATELIMIT;
++ net->next = ifp->allowednets;
++ net->subnet_mask = mask;
++ net->subnet_addr = subnet;
++ ifp->allowednets = net;
+
+-
+ // Debug log the result...
+ IF_DEBUG log( LOG_DEBUG, 0, "buildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s",
+- IfDescEp->Name,
+- fmtInAdr( FmtBu, IfDescEp->InAdr ),
+- IfDescEp->Flags,
++ ifp->Name,
++ fmtInAdr( FmtBu, ifp->InAdr ),
++ ifp->Flags,
+ inetFmts(subnet,mask, s1));
+
+- IfDescEp++;
+ }
+- }
+
+- close( Sock );
++ }
++ freeifaddrs(ifap);
+ }
+
+ /*
+--- src/igmp.c.orig 2005-05-24 16:49:16.000000000 +0100
++++ src/igmp.c 2009-03-18 14:35:31.000000000 +0000
+@@ -105,7 +105,7 @@
+ struct igmp *igmp;
+ int ipdatalen, iphdrlen, igmpdatalen;
+
+- if (recvlen < sizeof(struct ip)) {
++ if (recvlen < (int) sizeof(struct ip)) {
+ log(LOG_WARNING, 0,
+ "received packet too short (%u bytes) for IP header", recvlen);
+ return;
+@@ -128,6 +128,7 @@
+ }
+ else {
+ struct IfDesc *checkVIF;
++ int downIf = -1;
+
+ // Check if the source address matches a valid address on upstream vif.
+ checkVIF = getIfByIx( upStreamVif );
+@@ -141,23 +142,44 @@
+ return;
+ }
+ else if(!isAdressValidForIf(checkVIF, src)) {
+- log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.",
+- inetFmt(src, s1), inetFmt(dst, s2));
+- return;
++ unsigned Ix;
++ struct IfDesc *Dp;
++ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) {
++ if ((Dp->state == IF_STATE_DOWNSTREAM) &&isAdressValidForIf(Dp, src)) {
++ downIf = Ix;
++ break;
++ }
++ }
++
++ if (downIf == -1) {
++ log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.",
++ inetFmt(src, s1), inetFmt(dst, s2));
++ return;
++ } else {
++ log(LOG_NOTICE, 0, "The source address %s for group %s, is valid DOWNSTREAM VIF #%d.",
++ inetFmt(src, s1), inetFmt(dst, s2), downIf);
++ }
+ }
+
+ // Activate the route.
+- IF_DEBUG log(LOG_DEBUG, 0, "Route activate request from %s to %s",
+- inetFmt(src,s1), inetFmt(dst,s2));
+- activateRoute(dst, src);
++ IF_DEBUG log(LOG_DEBUG, 0, "Route activate request from %s to %s, downIf %d",
++ inetFmt(src,s1), inetFmt(dst,s2), downIf);
++ activateRoute(dst, src, downIf);
+
+
+ }
+ return;
+ }
+
++ log(LOG_DEBUG, 0, "Packet from %s: proto: %d hdrlen: %d iplen: %d or %d",
++ inetFmt(src, s1), ip->ip_p, ip->ip_hl << 2, ip->ip_len, ntohs(ip->ip_len));
++
+ iphdrlen = ip->ip_hl << 2;
++#ifdef RAW_INPUT_IS_RAW
+ ipdatalen = ntohs(ip->ip_len) - iphdrlen;
++#else
++ ipdatalen = ip->ip_len;
++#endif
+
+ if (iphdrlen + ipdatalen != recvlen) {
+ log(LOG_WARNING, 0,
+@@ -176,9 +198,9 @@
+ return;
+ }
+
+- log(LOG_NOTICE, 0, "RECV %s from %-15s to %s",
++ log(LOG_NOTICE, 0, "RECV %s from %-15s to %s (ip_hl %d, data %d)",
+ igmpPacketKind(igmp->igmp_type, igmp->igmp_code),
+- inetFmt(src, s1), inetFmt(dst, s2) );
++ inetFmt(src, s1), inetFmt(dst, s2), iphdrlen, ipdatalen);
+
+ switch (igmp->igmp_type) {
+ case IGMP_V1_MEMBERSHIP_REPORT:
+@@ -190,13 +212,10 @@
+ acceptLeaveMessage(src, group);
+ return;
+
+- /*
+ case IGMP_MEMBERSHIP_QUERY:
+ //accept_membership_query(src, dst, group, igmp->igmp_code);
+ return;
+
+- */
+-
+ default:
+ log(LOG_INFO, 0,
+ "ignoring unknown IGMP message type %x from %s to %s",
+@@ -220,8 +239,9 @@
+ ip->ip_src.s_addr = src;
+ ip->ip_dst.s_addr = dst;
+ ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
++#ifdef RAW_OUTPUT_IS_RAW
+ ip->ip_len = htons(ip->ip_len);
+-
++#endif
+ if (IN_MULTICAST(ntohl(dst))) {
+ ip->ip_ttl = curttl;
+ } else {
+--- src/igmpproxy.c.orig 2005-08-20 13:56:32.000000000 +0100
++++ src/igmpproxy.c 2009-03-18 14:35:31.000000000 +0000
+@@ -80,7 +80,7 @@
+ * on commandline. The number of commandline arguments, and a
+ * pointer to the arguments are recieved on the line...
+ */
+-int main( int ArgCn, const char *ArgVc[] ) {
++int main( int ArgCn, char *ArgVc[] ) {
+
+ int debugMode = 0;
+
+@@ -155,17 +155,8 @@
+ if ( ! debugMode ) {
+
+ IF_DEBUG log( LOG_DEBUG, 0, "Starting daemon mode.");
+-
+- // Only daemon goes past this line...
+- if (fork()) exit(0);
+-
+- // Detach deamon from terminal
+- if ( close( 0 ) < 0 || close( 1 ) < 0 || close( 2 ) < 0
+- || open( "/dev/null", 0 ) != 0 || dup2( 0, 1 ) < 0 || dup2( 0, 2 ) < 0
+- || setpgrp() < 0
+- ) {
++ if (daemon(1, 0) != 0)
+ log( LOG_ERR, errno, "failed to detach deamon" );
+- }
+ }
+
+ // Go to the main loop.
+@@ -218,7 +209,7 @@
+ int vifcount = 0;
+ upStreamVif = -1;
+
+- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) {
++ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) {
+
+ if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) {
+ if(Dp->state == IF_STATE_UPSTREAM) {
+@@ -237,7 +228,7 @@
+
+ // If there is only one VIF, or no defined upstream VIF, we send an error.
+ if(vifcount < 2 || upStreamVif < 0) {
+- log(LOG_ERR, 0, "There must be at least 2 Vif's where one is upstream.");
++ log(LOG_ERR, 0, "There must be at least 2 Vif's where one is upstream. (vifcount %d, upStreamVif %d)", vifcount, upStreamVif);
+ }
+ }
+
+@@ -275,7 +266,7 @@
+ register int recvlen;
+ int MaxFD, Rt, secs;
+ fd_set ReadFDS;
+- int dummy = 0;
++ socklen_t dummy = 0;
+ struct timeval curtime, lasttime, difftime, tv;
+ // The timeout is a pointer in order to set it to NULL if nessecary.
+ struct timeval *timeout = &tv;
+--- src/igmpproxy.conf.orig 2005-04-29 20:27:50.000000000 +0100
++++ src/igmpproxy.conf 2009-03-18 14:35:31.000000000 +0000
+@@ -25,22 +25,22 @@
+
+
+ ##------------------------------------------------------
+-## Configuration for eth0 (Upstream Interface)
++## Configuration for em0 (Upstream Interface)
+ ##------------------------------------------------------
+-phyint eth0 upstream ratelimit 0 threshold 1
++phyint em0 upstream ratelimit 0 threshold 1
+ altnet 10.0.0.0/8
+ altnet 192.168.0.0/24
+
+
+ ##------------------------------------------------------
+-## Configuration for eth1 (Downstream Interface)
++## Configuration for em1 (Downstream Interface)
+ ##------------------------------------------------------
+-phyint eth1 downstream ratelimit 0 threshold 1
++phyint em1 downstream ratelimit 0 threshold 1
+
+
+ ##------------------------------------------------------
+-## Configuration for eth2 (Disabled Interface)
++## Configuration for xl0 (Disabled Interface)
+ ##------------------------------------------------------
+-phyint eth2 disabled
++phyint xl0 disabled
+
+
+--- src/mcgroup.c.orig 2005-08-20 13:54:37.000000000 +0100
++++ src/mcgroup.c 2009-03-18 14:35:31.000000000 +0000
+@@ -49,7 +49,6 @@
+ CtlReq.imr_interface.s_addr = IfDp->InAdr.s_addr;
+
+ {
+- char FmtBu[ 32 ];
+ log( LOG_NOTICE, 0, "%sMcGroup: %s on %s", CmdSt,
+ inetFmt( mcastaddr, s1 ), IfDp ? IfDp->Name : "<any>" );
+ }
+--- src/mroute-api.c.orig 2005-05-24 16:48:33.000000000 +0100
++++ src/mroute-api.c 2009-03-18 14:35:31.000000000 +0000
+@@ -37,7 +37,9 @@
+ */
+
+
++#ifndef __FreeBSD__
+ #define USE_LINUX_IN_H
++#endif
+ #include "defs.h"
+
+ // MAX_MC_VIFS from mclab.h must have same value as MAXVIFS from mroute.h
+@@ -47,7 +49,7 @@
+
+ // need an IGMP socket as interface for the mrouted API
+ // - receives the IGMP messages
+-int MRouterFD; /* socket for all network I/O */
++int MRouterFD = -1; /* socket for all network I/O */
+ char *recv_buf; /* input packet buffer */
+ char *send_buf; /* output packet buffer */
+
+@@ -177,13 +179,15 @@
+ log( LOG_NOTICE, 0, "Adding MFC: %s -> %s, InpVIf: %d",
+ fmtInAdr( FmtBuO, CtlReq.mfcc_origin ),
+ fmtInAdr( FmtBuM, CtlReq.mfcc_mcastgrp ),
+- CtlReq.mfcc_parent == ALL_VIFS ? -1 : CtlReq.mfcc_parent
++ CtlReq.mfcc_parent
+ );
+ }
+
+ if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_ADD_MFC,
+ (void *)&CtlReq, sizeof( CtlReq ) ) )
+ log( LOG_WARNING, errno, "MRT_ADD_MFC" );
++
++ return 0;
+ }
+
+ /*
+@@ -210,13 +214,15 @@
+ log( LOG_NOTICE, 0, "Removing MFC: %s -> %s, InpVIf: %d",
+ fmtInAdr( FmtBuO, CtlReq.mfcc_origin ),
+ fmtInAdr( FmtBuM, CtlReq.mfcc_mcastgrp ),
+- CtlReq.mfcc_parent == ALL_VIFS ? -1 : CtlReq.mfcc_parent
++ CtlReq.mfcc_parent
+ );
+ }
+
+ if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_DEL_MFC,
+ (void *)&CtlReq, sizeof( CtlReq ) ) )
+ log( LOG_WARNING, errno, "MRT_DEL_MFC" );
++
++ return 0;
+ }
+
+ /*
+--- src/request.c.orig 2005-05-24 16:48:29.000000000 +0100
++++ src/request.c 2009-03-18 14:35:31.000000000 +0000
+@@ -88,10 +88,11 @@
+
+ } else {
+ // Log the state of the interface the report was recieved on.
+- log(LOG_INFO, 0, "Mebership report was recieved on %s. Ignoring.",
++ log(LOG_INFO, 0, "Membership report was received on %s. Ignoring.",
+ sourceVif->state==IF_STATE_UPSTREAM?"the upstream interface":"a disabled interface");
+ }
+
++ log(LOG_DEBUG, 0, "Eliminate compiler warning for field type = %u", type);
+ }
+
+ /**
+@@ -136,7 +137,7 @@
+
+ } else {
+ // just ignore the leave request...
+- IF_DEBUG log(LOG_DEBUG, 0, "The found if for %s was not downstream. Ignoring leave request.");
++ IF_DEBUG log(LOG_DEBUG, 0, "The found if for %s was not downstream. Ignoring leave request.", inetFmt(src, s1));
+ }
+ }
+
+@@ -184,7 +185,7 @@
+ int Ix;
+
+ // Loop through all downstream vifs...
+- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) {
++ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) {
+ if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) {
+ if(Dp->state == IF_STATE_DOWNSTREAM) {
+ // Send the membership query...
+--- src/rttable.c.orig 2005-08-20 13:46:20.000000000 +0100
++++ src/rttable.c 2009-03-18 14:35:31.000000000 +0000
+@@ -38,15 +38,22 @@
+ */
+
+ #include "defs.h"
++#include <sys/queue.h>
+
+ /**
+ * Routing table structure definition. Double linked list...
+ */
++struct Origin {
++ TAILQ_ENTRY(Origin) next;
++ uint32 originAddr;
++ int flood;
++ uint32 pktcnt;
++};
++
+ struct RouteTable {
+ struct RouteTable *nextroute; // Pointer to the next group in line.
+ struct RouteTable *prevroute; // Pointer to the previous group in line.
+ uint32 group; // The group to route
+- uint32 originAddr; // The origin adress (only set on activated routes)
+ uint32 vifBits; // Bits representing recieving VIFs.
+
+ // Keeps the upstream membership state...
+@@ -56,6 +63,7 @@
+ uint32 ageVifBits; // Bits representing aging VIFs.
+ int ageValue; // Downcounter for death.
+ int ageActivity; // Records any acitivity that notes there are still listeners.
++ TAILQ_HEAD(originhead, Origin) originList; // The origin adresses (non-empty on activated routes)
+ };
+
+
+@@ -65,19 +73,17 @@
+ // Prototypes
+ void logRouteTable(char *header);
+ int internAgeRoute(struct RouteTable* croute);
+-
+-// Socket for sending join or leave requests.
+-int mcGroupSock = 0;
++int internUpdateKernelRoute(struct RouteTable *route, int activate, struct Origin *o);
+
+
+ /**
+ * Function for retrieving the Multicast Group socket.
+ */
+ int getMcGroupSock() {
+- if( ! mcGroupSock ) {
+- mcGroupSock = openUdpSocket( INADDR_ANY, 0 );;
++ if (MRouterFD < 0) {
++ log(LOG_ERR, errno, "no MRouterFD.");
+ }
+- return mcGroupSock;
++ return MRouterFD;
+ }
+
+ /**
+@@ -91,7 +97,7 @@
+ routing_table = NULL;
+
+ // Join the all routers group on downstream vifs...
+- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) {
++ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) {
+ // If this is a downstream vif, we should join the All routers group...
+ if( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) && Dp->state == IF_STATE_DOWNSTREAM) {
+ IF_DEBUG log(LOG_DEBUG, 0, "Joining all-routers group %s on vif %s",
+@@ -160,6 +166,7 @@
+ */
+ void clearAllRoutes() {
+ struct RouteTable *croute, *remainroute;
++ struct Origin *o;
+
+ // Loop through all routes...
+ for(croute = routing_table; croute; croute = remainroute) {
+@@ -171,7 +178,7 @@
+ inetFmt(croute->group, s1));
+
+ // Uninstall current route
+- if(!internUpdateKernelRoute(croute, 0)) {
++ if(!internUpdateKernelRoute(croute, 0, NULL)) {
+ log(LOG_WARNING, 0, "The removal from Kernel failed.");
+ }
+
+@@ -179,6 +186,10 @@
+ sendJoinLeaveUpstream(croute, 0);
+
+ // Clear memory, and set pointer to next route...
++ while ((o = TAILQ_FIRST(&croute->originList))) {
++ TAILQ_REMOVE(&croute->originList, o, next);
++ free(o);
++ }
+ free(croute);
+ }
+ routing_table = NULL;
+@@ -212,7 +223,6 @@
+
+ struct Config *conf = getCommonConfig();
+ struct RouteTable* croute;
+- int result = 1;
+
+ // Sanitycheck the group adress...
+ if( ! IN_MULTICAST( ntohl(group) )) {
+@@ -241,7 +251,8 @@
+ newroute = (struct RouteTable*)malloc(sizeof(struct RouteTable));
+ // Insert the route desc and clear all pointers...
+ newroute->group = group;
+- newroute->originAddr = 0;
++ TAILQ_INIT(&newroute->originList);
++
+ newroute->nextroute = NULL;
+ newroute->prevroute = NULL;
+
+@@ -325,10 +336,10 @@
+ inetFmt(croute->group, s1), ifx);
+
+ // If the route is active, it must be reloaded into the Kernel..
+- if(croute->originAddr != 0) {
++ if(!TAILQ_EMPTY(&croute->originList)) {
+
+ // Update route in kernel...
+- if(!internUpdateKernelRoute(croute, 1)) {
++ if(!internUpdateKernelRoute(croute, 1, NULL)) {
+ log(LOG_WARNING, 0, "The insertion into Kernel failed.");
+ return 0;
+ }
+@@ -351,7 +362,7 @@
+ * activated, it's reinstalled in the kernel. If
+ * the route is activated, no originAddr is needed.
+ */
+-int activateRoute(uint32 group, uint32 originAddr) {
++int activateRoute(uint32 group, uint32 originAddr, int downIf) {
+ struct RouteTable* croute;
+ int result = 0;
+
+@@ -369,21 +380,42 @@
+ }
+
+ if(croute != NULL) {
++ struct Origin *o = NULL;
++ int found = 0;
++
+ // If the origin address is set, update the route data.
+- if(originAddr > 0) {
+- if(croute->originAddr > 0 && croute->originAddr!=originAddr) {
+- log(LOG_WARNING, 0, "The origin for route %s changed from %s to %s",
+- inetFmt(croute->group, s1),
+- inetFmt(croute->originAddr, s2),
+- inetFmt(originAddr, s3));
+- }
+- croute->originAddr = originAddr;
+- }
++ if(originAddr > 0) {
+
+- // Only update kernel table if there are listeners !
+- if(croute->vifBits > 0) {
+- result = internUpdateKernelRoute(croute, 1);
+- }
++ TAILQ_FOREACH(o, &croute->originList, next) {
++ log(LOG_INFO, 0, "Origin for route %s have %s, new %s",
++ inetFmt(croute->group, s1),
++ inetFmt(o->originAddr, s2),
++ inetFmt(originAddr, s3));
++ if (o->originAddr==originAddr) {
++ found++;
++ break;
++ }
++ }
++ if (!found) {
++ log(LOG_NOTICE, 0, "New origin for route %s is %s, flood %d",
++ inetFmt(croute->group, s1),
++ inetFmt(originAddr, s3), downIf);
++ o = malloc(sizeof(*o));
++ o->originAddr = originAddr;
++ o->flood = downIf;
++ o->pktcnt = 0;
++ TAILQ_INSERT_TAIL(&croute->originList, o, next);
++ } else {
++ log(LOG_INFO, 0, "Have origin for route %s at %s, pktcnt %d",
++ inetFmt(croute->group, s1),
++ inetFmt(o->originAddr, s3),
++ o->pktcnt);
++ }
++ }
++
++ // Only update kernel table if there are listeners, but flood upstream!
++ if(croute->vifBits > 0 || downIf >= 0)
++ result = internUpdateKernelRoute(croute, 1, o);
+ }
+ IF_DEBUG logRouteTable("Activate Route");
+
+@@ -443,7 +475,6 @@
+ * route is not found, or not in this state, 0 is returned.
+ */
+ int lastMemberGroupAge(uint32 group) {
+- struct Config *conf = getCommonConfig();
+ struct RouteTable *croute;
+
+ croute = findRoute(group);
+@@ -463,6 +494,7 @@
+ */
+ int removeRoute(struct RouteTable* croute) {
+ struct Config *conf = getCommonConfig();
++ struct Origin *o;
+ int result = 1;
+
+ // If croute is null, no routes was found.
+@@ -477,7 +509,7 @@
+ //BIT_ZERO(croute->vifBits);
+
+ // Uninstall current route from kernel
+- if(!internUpdateKernelRoute(croute, 0)) {
++ if(!internUpdateKernelRoute(croute, 0, NULL)) {
+ log(LOG_WARNING, 0, "The removal from Kernel failed.");
+ result = 0;
+ }
+@@ -503,7 +535,12 @@
+ croute->nextroute->prevroute = croute->prevroute;
+ }
+ }
++
+ // Free the memory, and set the route to NULL...
++ while ((o = TAILQ_FIRST(&croute->originList))) {
++ TAILQ_REMOVE(&croute->originList, o, next);
++ free(o);
++ }
+ free(croute);
+ croute = NULL;
+
+@@ -551,6 +588,36 @@
+ }
+ }
+
++ {
++ struct Origin *o, *nxt;
++ struct sioc_sg_req sg_req;
++
++ sg_req.grp.s_addr = croute->group;
++ for (o = TAILQ_FIRST(&croute->originList); o; o = nxt) {
++ nxt = TAILQ_NEXT(o, next);
++ sg_req.src.s_addr = o->originAddr;
++ if (ioctl(MRouterFD, SIOCGETSGCNT, (char *)&sg_req) < 0) {
++ log(LOG_WARNING, errno, "%s (%s %s)",
++ "age_table_entry: SIOCGETSGCNT failing for",
++ inetFmt(o->originAddr, s1),
++ inetFmt(croute->group, s2));
++ /* Make sure it gets deleted below */
++ sg_req.pktcnt = o->pktcnt;
++ }
++ log(LOG_DEBUG, 0, "Aging Origin %s Dst %s PktCnt %d -> %d",
++ inetFmt(o->originAddr, s1), inetFmt(croute->group, s2),
++ o->pktcnt, sg_req.pktcnt);
++ if (sg_req.pktcnt == o->pktcnt) {
++ /* no traffic, remove from kernel cache */
++ internUpdateKernelRoute(croute, 0, o);
++ TAILQ_REMOVE(&croute->originList, o, next);
++ free(o);
++ } else {
++ o->pktcnt = sg_req.pktcnt;
++ }
++ }
++ }
++
+ // If the aging counter has reached zero, its time for updating...
+ if(croute->ageValue == 0) {
+ // Check for activity in the aging process,
+@@ -560,7 +627,7 @@
+ inetFmt(croute->group,s1));
+
+ // Just update the routing settings in kernel...
+- internUpdateKernelRoute(croute, 1);
++ internUpdateKernelRoute(croute, 1, NULL);
+
+ // We append the activity counter to the age, and continue...
+ croute->ageValue = croute->ageActivity;
+@@ -586,34 +653,57 @@
+ /**
+ * Updates the Kernel routing table. If activate is 1, the route
+ * is (re-)activated. If activate is false, the route is removed.
++* if 'origin' is given, only the route with 'origin' will be
++* updated, otherwise all MFC routes for the group will updated.
+ */
+-int internUpdateKernelRoute(struct RouteTable *route, int activate) {
++int internUpdateKernelRoute(struct RouteTable *route, int activate, struct Origin *origin) {
+ struct MRouteDesc mrDesc;
+ struct IfDesc *Dp;
+ unsigned Ix;
+-
+- if(route->originAddr>0) {
++ struct Origin *o;
++
++ if (TAILQ_EMPTY(&route->originList)) {
++ log(LOG_NOTICE, 0, "Route is not active. No kernel updates done.");
++ return 1;
++ }
++ TAILQ_FOREACH(o, &route->originList, next) {
++ if (origin && origin != o)
++ continue;
+
+ // Build route descriptor from table entry...
+ // Set the source address and group address...
+ mrDesc.McAdr.s_addr = route->group;
+- mrDesc.OriginAdr.s_addr = route->originAddr;
++ mrDesc.OriginAdr.s_addr = o->originAddr;
+
+ // clear output interfaces
+ memset( mrDesc.TtlVc, 0, sizeof( mrDesc.TtlVc ) );
+
+- IF_DEBUG log(LOG_DEBUG, 0, "Vif bits : 0x%08x", route->vifBits);
+-
++ IF_DEBUG log(LOG_DEBUG, 0, "Origin %s Vif bits : 0x%08x", inetFmt(o->originAddr, s1), route->vifBits);
+ // Set the TTL's for the route descriptor...
+- for ( Ix = 0; Dp = getIfByIx( Ix ); Ix++ ) {
+- if(Dp->state == IF_STATE_UPSTREAM) {
+- //IF_DEBUG log(LOG_DEBUG, 0, "Identified VIF #%d as upstream.", Dp->index);
+- mrDesc.InVif = Dp->index;
+- }
+- else if(BIT_TST(route->vifBits, Dp->index)) {
+- IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for Vif %d to %d", Dp->index, Dp->threshold);
+- mrDesc.TtlVc[ Dp->index ] = Dp->threshold;
+- }
++ for ( Ix = 0; (Dp = getIfByIx( Ix )); Ix++ ) {
++ if (o->flood >= 0) {
++ if(Ix == (unsigned) o->flood) {
++ IF_DEBUG log(LOG_DEBUG, 0, "Identified Input VIF #%d as DOWNSTREAM.", Dp->index);
++ mrDesc.InVif = Dp->index;
++ }
++ else if(Dp->state == IF_STATE_UPSTREAM) {
++ IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for UPSTREAM Vif %d to %d", Dp->index, Dp->threshold);
++ mrDesc.TtlVc[ Dp->index ] = Dp->threshold;
++ }
++ else if(BIT_TST(route->vifBits, Dp->index)) {
++ IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for DOWNSTREAM Vif %d to %d", Dp->index, Dp->threshold);
++ mrDesc.TtlVc[ Dp->index ] = Dp->threshold;
++ }
++ } else {
++ if(Dp->state == IF_STATE_UPSTREAM) {
++ IF_DEBUG log(LOG_DEBUG, 0, "Identified VIF #%d as upstream.", Dp->index);
++ mrDesc.InVif = Dp->index;
++ }
++ else if(BIT_TST(route->vifBits, Dp->index)) {
++ IF_DEBUG log(LOG_DEBUG, 0, "Setting TTL for Vif %d to %d", Dp->index, Dp->threshold);
++ mrDesc.TtlVc[ Dp->index ] = Dp->threshold;
++ }
++ }
+ }
+
+ // Do the actual Kernel route update...
+@@ -625,9 +715,6 @@
+ // Delete the route from Kernel...
+ delMRoute( &mrDesc );
+ }
+-
+- } else {
+- log(LOG_NOTICE, 0, "Route is not active. No kernel updates done.");
+ }
+
+ return 1;
+@@ -647,16 +734,17 @@
+ log(LOG_DEBUG, 0, "No routes in table...");
+ } else {
+ do {
+- /*
+- log(LOG_DEBUG, 0, "#%d: Src: %s, Dst: %s, Age:%d, St: %s, Prev: 0x%08x, T: 0x%08x, Next: 0x%08x",
+- rcount, inetFmt(croute->originAddr, s1), inetFmt(croute->group, s2),
+- croute->ageValue,(croute->originAddr>0?"A":"I"),
+- croute->prevroute, croute, croute->nextroute);
+- */
+- log(LOG_DEBUG, 0, "#%d: Src: %s, Dst: %s, Age:%d, St: %s, OutVifs: 0x%08x",
+- rcount, inetFmt(croute->originAddr, s1), inetFmt(croute->group, s2),
+- croute->ageValue,(croute->originAddr>0?"A":"I"),
+- croute->vifBits);
++ log(LOG_DEBUG, 0, "#%d: Dst: %s, Age:%d, St: %s, OutVifs: 0x%08x",
++ rcount, inetFmt(croute->group, s2),
++ croute->ageValue,(TAILQ_EMPTY(&croute->originList)?"I":"A"),
++ croute->vifBits);
++ {
++ struct Origin *o;
++ TAILQ_FOREACH(o, &croute->originList, next) {
++ log(LOG_DEBUG, 0, "#%d: Origin: %s floodIf %d pktcnt %d",
++ rcount, inetFmt(o->originAddr, s1), o->flood, o->pktcnt);
++ }
++ }
+
+ croute = croute->nextroute;
+
+--- src/syslog.c.orig 2005-05-24 16:48:19.000000000 +0100
++++ src/syslog.c 2009-03-18 14:38:38.000000000 +0000
+@@ -53,12 +53,16 @@
+ ** is logged to 'stderr'.
+ **
+ */
++#ifdef DEVEL_LOGGING
++void _log( int Serverity, int Errno, const char *func, int line, const char *FmtSt, ... )
++#else
+ void log( int Serverity, int Errno, const char *FmtSt, ... )
++#endif
+ {
+ const char ServVc[][ 5 ] = { "EMER", "ALER", "CRIT", "ERRO",
+ "Warn", "Note", "Info", "Debu" };
+
+- const char *ServPt = Serverity < 0 || Serverity >= VCMC( ServVc ) ?
++ const char *ServPt = Serverity < 0 || Serverity >= (int) VCMC( ServVc ) ?
+ "!unknown serverity!" : ServVc[ Serverity ];
+
+ const char *ErrSt = (Errno <= 0) ? NULL : (const char *)strerror( Errno );
+@@ -69,6 +73,9 @@
+
+ va_start( ArgPt, FmtSt );
+ Ln = snprintf( LogLastMsg, sizeof( LogLastMsg ), "%s: ", ServPt );
++#ifdef DEVEL_LOGGING
++ Ln += snprintf( LogLastMsg + Ln, sizeof( LogLastMsg ) - Ln, "%s():%d: ", func, line);
++#endif
+ Ln += vsnprintf( LogLastMsg + Ln, sizeof( LogLastMsg ) - Ln, FmtSt, ArgPt );
+ if( ErrSt )
+ snprintf( LogLastMsg + Ln, sizeof( LogLastMsg ) - Ln, "; Errno(%d): %s", Errno, ErrSt );
diff --git a/net/igmpproxy/pkg-descr b/net/igmpproxy/pkg-descr
new file mode 100644
index 000000000000..8e911e24ae9a
--- /dev/null
+++ b/net/igmpproxy/pkg-descr
@@ -0,0 +1,5 @@
+igmpproxy is a simple multicast routing daemon based on mrouted. It uses IGMP
+forwarding to dynamically route multicast traffic.
+Reqiures multicast forwarding enabled
+
+WWW: http://igmpproxy.sourceforge.net/