diff options
author | James <> | 2015-11-04 11:49:21 +0000 |
---|---|---|
committer | James <> | 2015-11-04 11:49:21 +0000 |
commit | 716ca530e1c4515d8683c9d5be3d56b301758b66 (patch) | |
tree | 700eb5bcc1a462a5f21dcec15ce7c97ecfefa772 /package/network/services/igmpproxy | |
download | trunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.tar.gz trunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.tar.bz2 trunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.zip |
Diffstat (limited to 'package/network/services/igmpproxy')
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; ++ } ++} ++ |