aboutsummaryrefslogtreecommitdiffstats
path: root/package/network/services/igmpproxy
diff options
context:
space:
mode:
authorJames <>2015-11-04 11:49:21 +0000
committerJames <>2015-11-04 11:49:21 +0000
commit716ca530e1c4515d8683c9d5be3d56b301758b66 (patch)
tree700eb5bcc1a462a5f21dcec15ce7c97ecfefa772 /package/network/services/igmpproxy
downloadtrunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.tar.gz
trunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.tar.bz2
trunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.zip
trunk-47381HEADmaster
Diffstat (limited to 'package/network/services/igmpproxy')
-rw-r--r--package/network/services/igmpproxy/Makefile59
-rw-r--r--package/network/services/igmpproxy/files/igmpproxy.config11
-rw-r--r--package/network/services/igmpproxy/files/igmpproxy.init146
-rw-r--r--package/network/services/igmpproxy/patches/001-Send-IGMP-packets-with-IP-Router-Alert-option-RFC-21.patch79
-rw-r--r--package/network/services/igmpproxy/patches/002-Change-default-interface-state-to-disabled-wrt-29458.patch43
-rw-r--r--package/network/services/igmpproxy/patches/003-Restrict-igmp-reports-for-downstream-interfaces-wrt-.patch164
-rw-r--r--package/network/services/igmpproxy/patches/004-Restrict-igmp-reports-forwarding-to-upstream-interfa.patch62
-rw-r--r--package/network/services/igmpproxy/patches/010-missing_include.patch10
-rw-r--r--package/network/services/igmpproxy/patches/020-Silence-downstream-interface-igmp-messages.patch19
-rw-r--r--package/network/services/igmpproxy/patches/100-use-monotic-clock-instead-of-time-of-day.patch120
-rw-r--r--package/network/services/igmpproxy/patches/200-allow_wildcard_addr.patch24
-rw-r--r--package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch154
12 files changed, 891 insertions, 0 deletions
diff --git a/package/network/services/igmpproxy/Makefile b/package/network/services/igmpproxy/Makefile
new file mode 100644
index 0000000..03ad258
--- /dev/null
+++ b/package/network/services/igmpproxy/Makefile
@@ -0,0 +1,59 @@
+#
+# Copyright (C) 2006-2011 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=igmpproxy
+PKG_VERSION:=0.1
+PKG_RELEASE:=8
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@SF/igmpproxy
+PKG_MD5SUM:=c56f41ec195bc1fe016369bf74efc5a1
+PKG_MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+
+include $(INCLUDE_DIR)/package.mk
+
+PKG_FIXUP:=autoreconf
+PKG_LICENSE:=GPL-2.0+
+
+define Package/igmpproxy
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Routing and Redirection
+ DEPENDS:=+USE_GLIBC:librt
+ TITLE:=Multicast Routing Daemon
+ URL:=http://sourceforge.net/projects/igmpproxy
+endef
+
+define Package/igmpproxy/description
+ IGMPproxy is a simple dynamic Multicast Routing Daemon using
+ only IGMP signalling (Internet Group Management Protocol).
+endef
+
+define Package/igmpproxy/conffiles
+/etc/config/igmpproxy
+endef
+
+TARGET_CFLAGS += -Dlog=igmpproxy_log
+
+define Build/Compile
+ $(MAKE) -C $(PKG_BUILD_DIR)/src \
+ CC="$(TARGET_CC)" \
+ CFLAGS="$(TARGET_CFLAGS) -std=gnu99"
+endef
+
+define Package/igmpproxy/install
+ $(INSTALL_DIR) $(1)/etc/config
+ $(INSTALL_CONF) ./files/igmpproxy.config $(1)/etc/config/igmpproxy
+ $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_BIN) ./files/igmpproxy.init $(1)/etc/init.d/igmpproxy
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/igmpproxy $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,igmpproxy))
diff --git a/package/network/services/igmpproxy/files/igmpproxy.config b/package/network/services/igmpproxy/files/igmpproxy.config
new file mode 100644
index 0000000..d290632
--- /dev/null
+++ b/package/network/services/igmpproxy/files/igmpproxy.config
@@ -0,0 +1,11 @@
+config igmpproxy
+ option quickleave 1
+
+config phyint wan
+ option network wan
+ option direction upstream
+ list altnet 192.168.1.0/24
+
+config phyint lan
+ option network lan
+ option direction downstream
diff --git a/package/network/services/igmpproxy/files/igmpproxy.init b/package/network/services/igmpproxy/files/igmpproxy.init
new file mode 100644
index 0000000..d03f90f
--- /dev/null
+++ b/package/network/services/igmpproxy/files/igmpproxy.init
@@ -0,0 +1,146 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2010-2014 OpenWrt.org
+
+START=99
+USE_PROCD=1
+PROG=/usr/sbin/igmpproxy
+CONFIGFILE=/var/etc/igmpproxy.conf
+
+# igmpproxy supports both a debug mode and verbosity, which are very useful
+# when something isn't working.
+#
+# Debug mode will print everything to stdout instead of syslog. Generally
+# verbosity should NOT be set as it will quickly fill your syslog.
+#
+# Put any debug or verbosity options into IGMP_OPTS
+#
+# Examples:
+# OPTIONS="-d -v -v" - debug mode and very verbose, this will land in
+# stdout and not in syslog
+# OPTIONS="-v" - be verbose, this will write aditional information to syslog
+
+OPTIONS=""
+
+igmp_header() {
+ local quickleave
+ config_get_bool quickleave "$1" quickleave 0
+
+ mkdir -p /var/etc
+ rm -f /var/etc/igmpproxy.conf
+ [ $quickleave -gt 0 ] && echo "quickleave" >> /var/etc/igmpproxy.conf
+
+ [ -L /etc/igmpproxy.conf ] || ln -nsf /var/etc/igmpproxy.conf /etc/igmpproxy.conf
+}
+
+igmp_add_phyint() {
+ local network direction altnets device up
+
+ config_get network $1 network
+ config_get direction $1 direction
+ config_get altnets $1 altnet
+
+ local status="$(ubus -S call "network.interface.$network" status)"
+ [ -n "$status" ] || return
+
+ json_load "$status"
+ json_get_var device l3_device
+ json_get_var up up
+
+ [ -n "$device" -a "$up" = "1" ] || {
+ procd_append_param error "$network is not up"
+ return;
+ }
+
+ append netdevs "$device"
+
+ [[ "$direction" = "upstream" ]] && has_upstream=1
+
+ echo -e "\nphyint $device $direction ratelimit 0 threshold 1" >> /var/etc/igmpproxy.conf
+
+ if [ -n "$altnets" ]; then
+ local altnet
+ for altnet in $altnets; do
+ echo -e "\taltnet $altnet" >> /var/etc/igmpproxy.conf
+ done
+ fi
+}
+
+igmp_add_network() {
+ local network
+
+ config_get network $1 network
+ procd_add_interface_trigger "interface.*" $network /etc/init.d/igmpproxy reload
+}
+
+igmp_add_firewall_routing() {
+ config_get network $1 network
+ config_get direction $1 direction
+
+ [[ "$direction" = "downstream" ]] || return 0
+
+ json_add_object ""
+ json_add_string type rule
+ json_add_string src "$upstream"
+ json_add_string dest "$network"
+ json_add_string family ipv4
+ json_add_string proto udp
+ json_add_string dest_ip "224.0.0.0/4"
+ json_add_string target ACCEPT
+ json_close_object
+}
+
+igmp_add_firewall_network() {
+ config_get network $1 network
+ config_get direction $1 direction
+
+ json_add_object ""
+ json_add_string type rule
+ json_add_string src "$network"
+ json_add_string proto igmp
+ json_add_string target ACCEPT
+ json_close_object
+
+ [[ "$direction" = "upstream" ]] && {
+ upstream="$network"
+ config_foreach igmp_add_firewall_routing phyint
+ }
+}
+
+service_triggers() {
+ procd_add_reload_trigger "igmpproxy"
+}
+
+start_service() {
+ has_upstream=
+ netdevs=
+ config_load igmpproxy
+
+ config_foreach igmp_header igmpproxy
+ config_foreach igmp_add_phyint phyint
+ [ -n "$has_upstream" ] || return
+
+ procd_open_instance
+ procd_set_param command $PROG
+ [ -n "$OPTIONS" ] && procd_append_param $OPTIONS
+ procd_append_param command $CONFIGFILE
+ procd_set_param file $CONFIGFILE
+ procd_set_param netdev $netdevs
+ procd_set_param respawn
+ procd_open_trigger
+ config_foreach igmp_add_network phyint
+ procd_close_trigger
+
+ procd_open_data
+
+ json_add_array firewall
+ config_foreach igmp_add_firewall_network phyint
+ json_close_array
+
+ procd_close_data
+
+ procd_close_instance
+}
+
+service_started() {
+ procd_set_config_changed firewall
+}
diff --git a/package/network/services/igmpproxy/patches/001-Send-IGMP-packets-with-IP-Router-Alert-option-RFC-21.patch b/package/network/services/igmpproxy/patches/001-Send-IGMP-packets-with-IP-Router-Alert-option-RFC-21.patch
new file mode 100644
index 0000000..ffe1cf1
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/001-Send-IGMP-packets-with-IP-Router-Alert-option-RFC-21.patch
@@ -0,0 +1,79 @@
+From fed8c3db10bc9d3a1e799a774924c00522595d0c Mon Sep 17 00:00:00 2001
+From: Evgeny Yurchenko <evg.yurch@rogers.com>
+Date: Mon, 4 Jan 2010 05:13:59 +0500
+Subject: [PATCH] Send IGMP packets with IP Router Alert option [RFC 2113] included in IP header
+
+---
+ src/igmp.c | 17 ++++++++++++-----
+ src/igmpproxy.h | 1 +
+ 2 files changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/src/igmp.c b/src/igmp.c
+index a0cd27d..b547688 100644
+--- a/src/igmp.c
++++ b/src/igmp.c
+@@ -67,7 +67,7 @@ void initIgmp() {
+ * - Checksum (let the kernel fill it in)
+ */
+ ip->ip_v = IPVERSION;
+- ip->ip_hl = sizeof(struct ip) >> 2;
++ ip->ip_hl = (sizeof(struct ip) + 4) >> 2; /* +4 for Router Alert option */
+ ip->ip_tos = 0xc0; /* Internet Control */
+ ip->ip_ttl = MAXTTL; /* applies to unicasts only */
+ ip->ip_p = IPPROTO_IGMP;
+@@ -213,7 +213,7 @@ void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, i
+ ip = (struct ip *)send_buf;
+ ip->ip_src.s_addr = src;
+ ip->ip_dst.s_addr = dst;
+- ip_set_len(ip, MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen);
++ ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen);
+
+ if (IN_MULTICAST(ntohl(dst))) {
+ ip->ip_ttl = curttl;
+@@ -221,13 +221,20 @@ void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, i
+ ip->ip_ttl = MAXTTL;
+ }
+
+- igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
++ /* Add Router Alert option */
++ ((u_char*)send_buf+MIN_IP_HEADER_LEN)[0] = IPOPT_RA;
++ ((u_char*)send_buf+MIN_IP_HEADER_LEN)[1] = 0x04;
++ ((u_char*)send_buf+MIN_IP_HEADER_LEN)[2] = 0x00;
++ ((u_char*)send_buf+MIN_IP_HEADER_LEN)[3] = 0x00;
++
++ igmp = (struct igmp *)(send_buf + IP_HEADER_RAOPT_LEN);
+ igmp->igmp_type = type;
+ igmp->igmp_code = code;
+ igmp->igmp_group.s_addr = group;
+ igmp->igmp_cksum = 0;
+ igmp->igmp_cksum = inetChksum((u_short *)igmp,
+- IGMP_MINLEN + datalen);
++ IP_HEADER_RAOPT_LEN + datalen);
++
+ }
+
+ /*
+@@ -257,7 +264,7 @@ void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, in
+ #endif
+ sdst.sin_addr.s_addr = dst;
+ if (sendto(MRouterFD, send_buf,
+- MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen, 0,
++ IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen, 0,
+ (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
+ if (errno == ENETDOWN)
+ my_log(LOG_ERR, errno, "Sender VIF was down.");
+diff --git a/src/igmpproxy.h b/src/igmpproxy.h
+index 0de7791..4df8a79 100644
+--- a/src/igmpproxy.h
++++ b/src/igmpproxy.h
+@@ -64,6 +64,7 @@
+ #define MAX_IP_PACKET_LEN 576
+ #define MIN_IP_HEADER_LEN 20
+ #define MAX_IP_HEADER_LEN 60
++#define IP_HEADER_RAOPT_LEN 24
+
+ #define MAX_MC_VIFS 32 // !!! check this const in the specific includes
+
+--
+1.7.2.5
+
diff --git a/package/network/services/igmpproxy/patches/002-Change-default-interface-state-to-disabled-wrt-29458.patch b/package/network/services/igmpproxy/patches/002-Change-default-interface-state-to-disabled-wrt-29458.patch
new file mode 100644
index 0000000..d7550d7
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/002-Change-default-interface-state-to-disabled-wrt-29458.patch
@@ -0,0 +1,43 @@
+From 85e240727305b156097ee7aa0f0c4473a136291f Mon Sep 17 00:00:00 2001
+From: Constantin Baranov <const@mimas.ru>
+Date: Tue, 23 Feb 2010 21:08:02 +0400
+Subject: [PATCH] Change default interface state to disabled (wrt #2945877)
+
+---
+ src/ifvc.c | 2 +-
+ src/igmpproxy.c | 6 ++++--
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/src/ifvc.c b/src/ifvc.c
+index 545b3b4..9d7ee97 100644
+--- a/src/ifvc.c
++++ b/src/ifvc.c
+@@ -139,7 +139,7 @@ void buildIfVc() {
+ IfDescEp->allowednets->subnet_addr = subnet;
+
+ // Set the default params for the IF...
+- IfDescEp->state = IF_STATE_DOWNSTREAM;
++ IfDescEp->state = IF_STATE_DISABLED;
+ IfDescEp->robustness = DEFAULT_ROBUSTNESS;
+ IfDescEp->threshold = DEFAULT_THRESHOLD; /* ttl limit */
+ IfDescEp->ratelimit = DEFAULT_RATELIMIT;
+diff --git a/src/igmpproxy.c b/src/igmpproxy.c
+index 1ece15a..35000c7 100644
+--- a/src/igmpproxy.c
++++ b/src/igmpproxy.c
+@@ -186,8 +186,10 @@ int igmpProxyInit() {
+ }
+ }
+
+- addVIF( Dp );
+- vifcount++;
++ if (Dp->state != IF_STATE_DISABLED) {
++ addVIF( Dp );
++ vifcount++;
++ }
+ }
+ }
+
+--
+1.7.2.5
+
diff --git a/package/network/services/igmpproxy/patches/003-Restrict-igmp-reports-for-downstream-interfaces-wrt-.patch b/package/network/services/igmpproxy/patches/003-Restrict-igmp-reports-for-downstream-interfaces-wrt-.patch
new file mode 100644
index 0000000..90d4d5f
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/003-Restrict-igmp-reports-for-downstream-interfaces-wrt-.patch
@@ -0,0 +1,164 @@
+From 65f777e7f66b55239d935c1cf81bb5abc0f6c89f Mon Sep 17 00:00:00 2001
+From: Grinch <grinch79@users.sourceforge.net>
+Date: Sun, 16 Aug 2009 19:58:26 +0500
+Subject: [PATCH] Restrict igmp reports for downstream interfaces (wrt #2833339)
+
+atm all igmp membership reports are forwarded to the upstream interface.
+Unfortunately some ISP Providers restrict some multicast groups (esp. those
+that are defined as local link groups and that are not supposed to be
+forwarded to the wan, i.e 224.0.0.0/24). Therefore there should be some
+kind of black oder whitelisting.
+As whitelisting can be accomplished quite easy I wrote a litte patch, which
+is attached to this request.
+---
+ doc/igmpproxy.conf.5.in | 19 +++++++++++++++++++
+ src/config.c | 23 ++++++++++++++++++++++-
+ src/igmpproxy.h | 1 +
+ src/request.c | 20 ++++++++++++++++----
+ 4 files changed, 58 insertions(+), 5 deletions(-)
+
+diff --git a/doc/igmpproxy.conf.5.in b/doc/igmpproxy.conf.5.in
+index a4ea7d0..56efa22 100644
+--- a/doc/igmpproxy.conf.5.in
++++ b/doc/igmpproxy.conf.5.in
+@@ -116,6 +116,25 @@ This is especially useful for the upstream interface, since the source for multi
+ traffic is often from a remote location. Any number of altnet parameters can be specified.
+ .RE
+
++.B whitelist
++.I networkaddr
++.RS
++Defines a whitelist for multicast groups. The network address must be in the following
++format 'a.b.c.d/n'. If you want to allow one single group use a network mask of /32,
++i.e. 'a.b.c.d/32'.
++
++By default all multicast groups are allowed on any downstream interface. If at least one
++whitelist entry is defined, all igmp membership reports for not explicitly whitelisted
++multicast groups will be ignored and therefore not be served by igmpproxy. This is especially
++useful, if your provider does only allow a predefined set of multicast groups. These whitelists
++are only obeyed by igmpproxy itself, they won't prevent any other igmp client running on the
++same machine as igmpproxy from requesting 'unallowed' multicast groups.
++
++You may specify as many whitelist entries as needed. Although you should keep it as simple as
++possible, as this list is parsed for every membership report and therefore this increases igmp
++response times. Often used or large groups should be defined first, as parsing ends as soon as
++a group matches an entry.
++.RE
+
+ .SH EXAMPLE
+ ## Enable quickleave
+diff --git a/src/config.c b/src/config.c
+index 5a96ce0..d72619f 100644
+--- a/src/config.c
++++ b/src/config.c
+@@ -46,6 +46,9 @@ struct vifconfig {
+
+ // Keep allowed nets for VIF.
+ struct SubnetList* allowednets;
++
++ // Allowed Groups
++ struct SubnetList* allowedgroups;
+
+ // Next config in list...
+ struct vifconfig* next;
+@@ -202,6 +205,8 @@ void configureVifs() {
+ // Insert the configured nets...
+ vifLast->next = confPtr->allowednets;
+
++ Dp->allowedgroups = confPtr->allowedgroups;
++
+ break;
+ }
+ }
+@@ -215,7 +220,7 @@ void configureVifs() {
+ */
+ struct vifconfig *parsePhyintToken() {
+ struct vifconfig *tmpPtr;
+- struct SubnetList **anetPtr;
++ struct SubnetList **anetPtr, **agrpPtr;
+ char *token;
+ short parseError = 0;
+
+@@ -239,6 +244,7 @@ struct vifconfig *parsePhyintToken() {
+ tmpPtr->threshold = 1;
+ tmpPtr->state = IF_STATE_DOWNSTREAM;
+ tmpPtr->allowednets = NULL;
++ tmpPtr->allowedgroups = NULL;
+
+ // Make a copy of the token to store the IF name
+ tmpPtr->name = strdup( token );
+@@ -248,6 +254,7 @@ struct vifconfig *parsePhyintToken() {
+
+ // Set the altnet pointer to the allowednets pointer.
+ anetPtr = &tmpPtr->allowednets;
++ agrpPtr = &tmpPtr->allowedgroups;
+
+ // Parse the rest of the config..
+ token = nextConfigToken();
+@@ -266,6 +273,20 @@ struct vifconfig *parsePhyintToken() {
+ anetPtr = &(*anetPtr)->next;
+ }
+ }
++ else if(strcmp("whitelist", token)==0) {
++ // Whitelist
++ token = nextConfigToken();
++ my_log(LOG_DEBUG, 0, "Config: IF: Got whitelist token %s.", token);
++
++ *agrpPtr = parseSubnetAddress(token);
++ if(*agrpPtr == NULL) {
++ parseError = 1;
++ my_log(LOG_WARNING, 0, "Unable to parse subnet address.");
++ break;
++ } else {
++ agrpPtr = &(*agrpPtr)->next;
++ }
++ }
+ else if(strcmp("upstream", token)==0) {
+ // Upstream
+ my_log(LOG_DEBUG, 0, "Config: IF: Got upstream token.");
+diff --git a/src/igmpproxy.h b/src/igmpproxy.h
+index 4dabd1c..0de7791 100644
+--- a/src/igmpproxy.h
++++ b/src/igmpproxy.h
+@@ -145,6 +145,7 @@ struct IfDesc {
+ short Flags;
+ short state;
+ struct SubnetList* allowednets;
++ struct SubnetList* allowedgroups;
+ unsigned int robustness;
+ unsigned char threshold; /* ttl limit */
+ unsigned int ratelimit;
+diff --git a/src/request.c b/src/request.c
+index e3589f6..89b91de 100644
+--- a/src/request.c
++++ b/src/request.c
+@@ -82,10 +82,22 @@ void acceptGroupReport(uint32_t src, uint32_t group, uint8_t type) {
+ my_log(LOG_DEBUG, 0, "Should insert group %s (from: %s) to route table. Vif Ix : %d",
+ inetFmt(group,s1), inetFmt(src,s2), sourceVif->index);
+
+- // The membership report was OK... Insert it into the route table..
+- insertRoute(group, sourceVif->index);
+-
+-
++ // If we don't have a whitelist we insertRoute and done
++ if(sourceVif->allowedgroups == NULL)
++ {
++ insertRoute(group, sourceVif->index);
++ return;
++ }
++ // Check if this Request is legit on this interface
++ struct SubnetList *sn;
++ for(sn = sourceVif->allowedgroups; sn != NULL; sn = sn->next)
++ if((group & sn->subnet_mask) == sn->subnet_addr)
++ {
++ // The membership report was OK... Insert it into the route table..
++ insertRoute(group, sourceVif->index);
++ return;
++ }
++ my_log(LOG_INFO, 0, "The group address %s may not be requested from this interface. Ignoring.", inetFmt(group, s1));
+ } else {
+ // Log the state of the interface the report was recieved on.
+ my_log(LOG_INFO, 0, "Mebership report was recieved on %s. Ignoring.",
+--
+1.7.2.5
+
diff --git a/package/network/services/igmpproxy/patches/004-Restrict-igmp-reports-forwarding-to-upstream-interfa.patch b/package/network/services/igmpproxy/patches/004-Restrict-igmp-reports-forwarding-to-upstream-interfa.patch
new file mode 100644
index 0000000..a4caed7
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/004-Restrict-igmp-reports-forwarding-to-upstream-interfa.patch
@@ -0,0 +1,62 @@
+From bcd7c648e86d97263c931de53a008c9629e7797e Mon Sep 17 00:00:00 2001
+From: Stefan Becker <stefan.becker@nokia.com>
+Date: Fri, 11 Dec 2009 21:08:57 +0200
+Subject: [PATCH] Restrict igmp reports forwarding to upstream interface
+
+Utilize the new "whitelist" keyword also on the upstream interface definition.
+If specified then only whitelisted multicast groups will be forwarded upstream.
+
+This can be used to avoid publishing private multicast groups to the world,
+e.g. SSDP from a UPnP server on the internal network.
+---
+ doc/igmpproxy.conf.5.in | 5 +++++
+ src/rttable.c | 17 +++++++++++++++++
+ 2 files changed, 22 insertions(+), 0 deletions(-)
+
+diff --git a/doc/igmpproxy.conf.5.in b/doc/igmpproxy.conf.5.in
+index 56efa22..d916f05 100644
+--- a/doc/igmpproxy.conf.5.in
++++ b/doc/igmpproxy.conf.5.in
+@@ -134,6 +134,11 @@ You may specify as many whitelist entries as needed. Although you should keep it
+ possible, as this list is parsed for every membership report and therefore this increases igmp
+ response times. Often used or large groups should be defined first, as parsing ends as soon as
+ a group matches an entry.
++
++You may also specify whitelist entries for the upstream interface. Only igmp membership reports
++for explicitely whitelisted multicast groups will be sent out on the upstream interface. This
++is useful if you want to use multicast groups only between your downstream interfaces, like SSDP
++from a UPnP server.
+ .RE
+
+ .SH EXAMPLE
+diff --git a/src/rttable.c b/src/rttable.c
+index f0701a8..77dd791 100644
+--- a/src/rttable.c
++++ b/src/rttable.c
+@@ -117,6 +117,23 @@ void sendJoinLeaveUpstream(struct RouteTable* route, int join) {
+ my_log(LOG_ERR, 0 ,"FATAL: Unable to get Upstream IF.");
+ }
+
++ // Check if there is a white list for the upstram VIF
++ if (upstrIf->allowedgroups != NULL) {
++ uint32_t group = route->group;
++ struct SubnetList* sn;
++
++ // Check if this Request is legit to be forwarded to upstream
++ for(sn = upstrIf->allowedgroups; sn != NULL; sn = sn->next)
++ if((group & sn->subnet_mask) == sn->subnet_addr)
++ // Forward is OK...
++ break;
++
++ if (sn == NULL) {
++ my_log(LOG_INFO, 0, "The group address %s may not be forwarded upstream. Ignoring.", inetFmt(group, s1));
++ return;
++ }
++ }
++
+ // Send join or leave request...
+ if(join) {
+
+--
+1.7.2.5
+
diff --git a/package/network/services/igmpproxy/patches/010-missing_include.patch b/package/network/services/igmpproxy/patches/010-missing_include.patch
new file mode 100644
index 0000000..af0eab8
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/010-missing_include.patch
@@ -0,0 +1,10 @@
+--- a/src/os-linux.h
++++ b/src/os-linux.h
+@@ -3,6 +3,7 @@
+ #include <linux/mroute.h>
+ #include <netinet/ip.h>
+ #include <netinet/igmp.h>
++#include <sys/types.h>
+
+ static inline u_short ip_data_len(const struct ip *ip)
+ {
diff --git a/package/network/services/igmpproxy/patches/020-Silence-downstream-interface-igmp-messages.patch b/package/network/services/igmpproxy/patches/020-Silence-downstream-interface-igmp-messages.patch
new file mode 100644
index 0000000..ccd000c
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/020-Silence-downstream-interface-igmp-messages.patch
@@ -0,0 +1,19 @@
+--- a/src/igmp.c
++++ b/src/igmp.c
+@@ -139,8 +139,14 @@
+ return;
+ }
+ else if(!isAdressValidForIf(checkVIF, src)) {
+- my_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));
++ struct IfDesc *downVIF = getIfByAddress(src);
++ if (downVIF && downVIF->state & IF_STATE_DOWNSTREAM) {
++ my_log(LOG_NOTICE, 0, "The source address %s for group %s is from downstream VIF. Ignoring.",
++ inetFmt(src, s1), inetFmt(dst, s2));
++ } else {
++ my_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;
+ }
+
diff --git a/package/network/services/igmpproxy/patches/100-use-monotic-clock-instead-of-time-of-day.patch b/package/network/services/igmpproxy/patches/100-use-monotic-clock-instead-of-time-of-day.patch
new file mode 100644
index 0000000..e75283c
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/100-use-monotic-clock-instead-of-time-of-day.patch
@@ -0,0 +1,120 @@
+From d0e66e0719ae8eb549f7cc220fdc66575d3db332 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jonas.gorski@gmail.com>
+Date: Thu, 29 Mar 2012 17:01:11 +0200
+Subject: [PATCH 4/4] use monotic clock instead of time of day
+
+The time of day might chance e.g. by daylight savings time during the
+runtime, which causes timers to fire repeatedly for a long time.
+
+Contributed by T-Labs, Deutsche Telekom Innovation Laboratories
+
+Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
+---
+ configure.ac | 2 ++
+ src/igmpproxy.c | 26 +++++++++++++-------------
+ src/igmpproxy.h | 3 ++-
+ 3 files changed, 17 insertions(+), 14 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 85beb08..bd84eba 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -25,6 +25,8 @@ AC_CHECK_MEMBERS([struct sockaddr_in.sin_len], [], [], [[
+ #include <netinet/in.h>
+ ]])
+
++AC_SEARCH_LIBS([clock_gettime],[rt])
++
+ AC_CONFIG_FILES([
+ Makefile
+ doc/Makefile
+diff --git a/src/igmpproxy.c b/src/igmpproxy.c
+index 35000c7..3a9ccad 100644
+--- a/src/igmpproxy.c
++++ b/src/igmpproxy.c
+@@ -234,13 +234,13 @@ void igmpProxyRun() {
+ int MaxFD, Rt, secs;
+ fd_set ReadFDS;
+ socklen_t dummy = 0;
+- struct timeval curtime, lasttime, difftime, tv;
++ struct timespec curtime, lasttime, difftime, tv;
+ // The timeout is a pointer in order to set it to NULL if nessecary.
+- struct timeval *timeout = &tv;
++ struct timespec *timeout = &tv;
+
+ // Initialize timer vars
+- difftime.tv_usec = 0;
+- gettimeofday(&curtime, NULL);
++ difftime.tv_nsec = 0;
++ clock_gettime(CLOCK_MONOTONIC, &curtime);
+ lasttime = curtime;
+
+ // First thing we send a membership query in downstream VIF's...
+@@ -263,7 +263,7 @@ void igmpProxyRun() {
+ if(secs == -1) {
+ timeout = NULL;
+ } else {
+- timeout->tv_usec = 0;
++ timeout->tv_nsec = 0;
+ timeout->tv_sec = secs;
+ }
+
+@@ -274,7 +274,7 @@ void igmpProxyRun() {
+ FD_SET( MRouterFD, &ReadFDS );
+
+ // wait for input
+- Rt = select( MaxFD +1, &ReadFDS, NULL, NULL, timeout );
++ Rt = pselect( MaxFD +1, &ReadFDS, NULL, NULL, timeout, NULL );
+
+ // log and ignore failures
+ if( Rt < 0 ) {
+@@ -307,20 +307,20 @@ void igmpProxyRun() {
+ */
+ if (Rt == 0) {
+ curtime.tv_sec = lasttime.tv_sec + secs;
+- curtime.tv_usec = lasttime.tv_usec;
++ curtime.tv_nsec = lasttime.tv_nsec;
+ Rt = -1; /* don't do this next time through the loop */
+ } else {
+- gettimeofday(&curtime, NULL);
++ clock_gettime(CLOCK_MONOTONIC, &curtime);
+ }
+ difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec;
+- difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec;
+- while (difftime.tv_usec > 1000000) {
++ difftime.tv_nsec += curtime.tv_nsec - lasttime.tv_nsec;
++ while (difftime.tv_nsec > 1000000000) {
+ difftime.tv_sec++;
+- difftime.tv_usec -= 1000000;
++ difftime.tv_nsec -= 1000000000;
+ }
+- if (difftime.tv_usec < 0) {
++ if (difftime.tv_nsec < 0) {
+ difftime.tv_sec--;
+- difftime.tv_usec += 1000000;
++ difftime.tv_nsec += 1000000000;
+ }
+ lasttime = curtime;
+ if (secs == 0 || difftime.tv_sec > 0)
+diff --git a/src/igmpproxy.h b/src/igmpproxy.h
+index 4df8a79..36a4f04 100644
+--- a/src/igmpproxy.h
++++ b/src/igmpproxy.h
+@@ -44,12 +44,13 @@
+ #include <string.h>
+ #include <fcntl.h>
+ #include <stdbool.h>
++#include <time.h>
+
+ #include <sys/socket.h>
+ #include <sys/un.h>
+-#include <sys/time.h>
+ #include <sys/ioctl.h>
+ #include <sys/param.h>
++#include <sys/select.h>
+
+ #include <net/if.h>
+ #include <netinet/in.h>
+--
+1.7.2.5
+
diff --git a/package/network/services/igmpproxy/patches/200-allow_wildcard_addr.patch b/package/network/services/igmpproxy/patches/200-allow_wildcard_addr.patch
new file mode 100644
index 0000000..0dd7720
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/200-allow_wildcard_addr.patch
@@ -0,0 +1,24 @@
+--- a/src/config.c
++++ b/src/config.c
+@@ -357,15 +357,18 @@ struct SubnetList *parseSubnetAddress(ch
+ tmpStr = strtok(NULL, "/");
+ if(tmpStr != NULL) {
+ int bitcnt = atoi(tmpStr);
+- if(bitcnt <= 0 || bitcnt > 32) {
++ if(bitcnt < 0 || bitcnt > 32) {
+ my_log(LOG_WARNING, 0, "The bits part of the address is invalid : %d.",tmpStr);
+ return NULL;
+ }
+
+- mask <<= (32 - bitcnt);
++ if (bitcnt == 0)
++ mask = 0;
++ else
++ mask <<= (32 - bitcnt);
+ }
+
+- if(addr == -1 || addr == 0) {
++ if(addr == -1) {
+ my_log(LOG_WARNING, 0, "Unable to parse address token '%s'.", addrstr);
+ return NULL;
+ }
diff --git a/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch b/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch
new file mode 100644
index 0000000..24aefce
--- /dev/null
+++ b/package/network/services/igmpproxy/patches/250-fix_multiple_downlink_interfaces.patch
@@ -0,0 +1,154 @@
+--- a/src/igmpproxy.h
++++ b/src/igmpproxy.h
+@@ -251,6 +251,7 @@ int activateRoute(uint32_t group, uint32
+ void ageActiveRoutes();
+ void setRouteLastMemberMode(uint32_t group);
+ int lastMemberGroupAge(uint32_t group);
++int interfaceInRoute(int32_t group, int Ix);
+
+ /* request.c
+ */
+--- a/src/request.c
++++ b/src/request.c
+@@ -41,10 +41,10 @@
+
+ // Prototypes...
+ void sendGroupSpecificMemberQuery(void *argument);
+-
++
+ typedef struct {
+ uint32_t group;
+- uint32_t vifAddr;
++ // uint32_t vifAddr;
+ short started;
+ } GroupVifDesc;
+
+@@ -142,7 +142,7 @@ void acceptLeaveMessage(uint32_t src, ui
+
+ // Call the group spesific membership querier...
+ gvDesc->group = group;
+- gvDesc->vifAddr = sourceVif->InAdr.s_addr;
++ // gvDesc->vifAddr = sourceVif->InAdr.s_addr;
+ gvDesc->started = 0;
+
+ sendGroupSpecificMemberQuery(gvDesc);
+@@ -159,6 +159,9 @@ void acceptLeaveMessage(uint32_t src, ui
+ */
+ void sendGroupSpecificMemberQuery(void *argument) {
+ struct Config *conf = getCommonConfig();
++ struct IfDesc *Dp;
++ struct RouteTable *croute;
++ int Ix;
+
+ // Cast argument to correct type...
+ GroupVifDesc *gvDesc = (GroupVifDesc*) argument;
+@@ -166,22 +169,38 @@ void sendGroupSpecificMemberQuery(void *
+ if(gvDesc->started) {
+ // If aging returns false, we don't do any further action...
+ if(!lastMemberGroupAge(gvDesc->group)) {
++ // FIXME: Should we free gvDesc here?
+ return;
+ }
+ } else {
+ gvDesc->started = 1;
+ }
+
+- // Send a group specific membership query...
+- sendIgmp(gvDesc->vifAddr, gvDesc->group,
+- IGMP_MEMBERSHIP_QUERY,
+- conf->lastMemberQueryInterval * IGMP_TIMER_SCALE,
+- gvDesc->group, 0);
+-
+- my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
+- inetFmt(gvDesc->vifAddr,s1), inetFmt(gvDesc->group,s2),
+- conf->lastMemberQueryInterval);
+-
++ /**
++ * FIXME: This loops through all interfaces the group is active on an sends queries.
++ * It might be better to send only a query on the interface the leave was accepted on and remove only that interface from the route.
++ */
++
++ // Loop through all downstream interfaces
++ for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
++ if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) {
++ if(Dp->state == IF_STATE_DOWNSTREAM) {
++ // Is that interface used in the group?
++ if (interfaceInRoute(gvDesc->group ,Dp->index)) {
++
++ // Send a group specific membership query...
++ sendIgmp(Dp->InAdr.s_addr, gvDesc->group,
++ IGMP_MEMBERSHIP_QUERY,
++ conf->lastMemberQueryInterval * IGMP_TIMER_SCALE,
++ gvDesc->group, 0);
++
++ my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
++ inetFmt(Dp->InAdr.s_addr,s1), inetFmt(gvDesc->group,s2),
++ conf->lastMemberQueryInterval);
++ }
++ }
++ }
++ }
+ // Set timeout for next round...
+ timer_setTimer(conf->lastMemberQueryInterval, sendGroupSpecificMemberQuery, gvDesc);
+
+--- a/src/rttable.c
++++ b/src/rttable.c
+@@ -428,6 +428,25 @@ void ageActiveRoutes() {
+ }
+
+ /**
++* Counts the number of interfaces a given route is active on
++*/
++int numberOfInterfaces(struct RouteTable *croute) {
++ int Ix;
++ struct IfDesc *Dp;
++ int result = 0;
++ // Loop through all interfaces
++ for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
++ // If the interface is used by the route, increase counter
++ if(BIT_TST(croute->vifBits, Dp->index)) {
++ result++;
++ }
++ }
++ my_log(LOG_DEBUG, 0, "counted %d interfaces", result);
++ return result;
++}
++
++
++/**
+ * Should be called when a leave message is recieved, to
+ * mark a route for the last member probe state.
+ */
+@@ -439,8 +458,11 @@ void setRouteLastMemberMode(uint32_t gro
+ if(croute!=NULL) {
+ // Check for fast leave mode...
+ if(croute->upstrState == ROUTESTATE_JOINED && conf->fastUpstreamLeave) {
+- // Send a leave message right away..
+- sendJoinLeaveUpstream(croute, 0);
++ // Send a leave message right away only when the route has been active on only one interface
++ if (numberOfInterfaces(croute) <= 1) {
++ my_log(LOG_DEBUG, 0, "Leaving group %d now", group);
++ sendJoinLeaveUpstream(croute, 0);
++ }
+ }
+ // Set the routingstate to Last member check...
+ croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER;
+@@ -677,3 +699,18 @@ void logRouteTable(char *header) {
+
+ my_log(LOG_DEBUG, 0, "-----------------------------------------------------");
+ }
++
++/**
++* Returns true when the given group belongs to the given interface
++*/
++int interfaceInRoute(int32_t group, int Ix) {
++ struct RouteTable* croute;
++ croute = findRoute(group);
++ if (croute != NULL) {
++ my_log(LOG_DEBUG, 0, "Interface id %d is in group $d", Ix, group);
++ return BIT_TST(croute->vifBits, Ix);
++ } else {
++ return 0;
++ }
++}
++