ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/external/routing/mcproxy/Makefile b/external/routing/mcproxy/Makefile
new file mode 100644
index 0000000..153e17a
--- /dev/null
+++ b/external/routing/mcproxy/Makefile
@@ -0,0 +1,58 @@
+#
+# Copyright (C) 2014-2017 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:=mcproxy
+PKG_SOURCE_VERSION:=93b5ace42268160ebbfff4c61818fb15fa2d9b99
+PKG_VERSION:=2017-08-24-$(PKG_SOURCE_VERSION)
+PKG_RELEASE:=3
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/mcproxy/mcproxy.git
+PKG_MIRROR_HASH:=5779a78dedaef491825ada632fe6d8282067025dede41d0eede5c441893a2994
+PKG_MAINTAINER:=Steven Barth <cyrus@openwrt.org>
+PKG_LICENSE:=GPL-2.0+
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/mcproxy
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Routing and Redirection
+ TITLE:=Multicast Proxy for IGMP/MLD
+ URL:=http://mcproxy.realmv6.org
+ DEPENDS:=+libpthread +libstdcpp @(!GCC_VERSION_4_4&&!GCC_VERSION_4_6)
+endef
+
+define Package/mcproxy/description
+ mcproxy is a free & open source implementation of the IGMP/MLD proxy function (see RFC 4605) for Linux systems.
+ It operates on the kernel tables for multicast routing and allows for multiple instantiations,
+ as well as dynamically changing downstream interfaces.
+endef
+
+define Package/mcproxy/conffiles
+/etc/mcproxy.conf
+/etc/config/mcproxy
+endef
+
+define Package/mcproxy/install
+ $(INSTALL_DIR) $(1)/etc
+ $(INSTALL_CONF) ./files/mcproxy.conf $(1)/etc/mcproxy.conf
+ $(INSTALL_DIR) $(1)/etc/config
+ $(INSTALL_CONF) ./files/mcproxy.config $(1)/etc/config/mcproxy
+ $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_BIN) ./files/mcproxy.init $(1)/etc/init.d/mcproxy
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/mcproxy-bin $(1)/usr/sbin/mcproxy
+endef
+
+$(eval $(call BuildPackage,mcproxy))
diff --git a/external/routing/mcproxy/files/mcproxy.conf b/external/routing/mcproxy/files/mcproxy.conf
new file mode 100644
index 0000000..936cdda
--- /dev/null
+++ b/external/routing/mcproxy/files/mcproxy.conf
@@ -0,0 +1,68 @@
+######################################
+##-- mcproxy configuration script --##
+######################################
+
+# Protocol: IGMPv1|IGMPv2|IGMPv3 (IPv4) - MLDv1|MLDv2 (IPv6)
+protocol IGMPv3;
+
+###########################################
+
+# Proxy Instance: upstream ==> downstream
+pinstance A: ap a1 ==> ap a2;
+pinstance B: bp b1 ==> bp b2;
+
+###########################################
+
+# Tables
+table allways {
+ (*|*)
+};
+
+table piA_peering_ifs {
+ ap(*|*)
+};
+
+table piA_upstreams {
+ a1(*|*)
+};
+
+table piB_peering_ifs {
+ bp(*|*)
+};
+
+table piB_upstreams {
+ b1(*|*)
+};
+
+###########################################
+
+# Instance Behaviour
+pinstance A upstream * in rulematching mutex 10; #or 25ms (u4)
+#pinstance A upstream * out rulematching all; #default
+
+pinstance A upstream ap out blacklist table allways; #(u1)
+#pinstance A upstream ap in whitelist table {(*|*)}; #default (u2, u3)
+
+pinstance A upstream a1 out blacklist table piA_peering_ifs; #(u3_1)
+#pinstance A upstream a1 in whitelist table {(*|*)}; #default
+
+pinstance A downstream ap in blacklist table allways; #(d1)
+pinstance A downstream ap out blacklist table piA_upstreams; #(d2, d2_1, d3, d4)
+
+#pinstance A downstream a2 in whitelist table {(*|*)}; #default
+#pinstance A downstream a2 out whitelist table {(*|*)}; #default
+
+pinstance B upstream * in rulematching mutex 10; #or 25ms (u4)
+#pinstance B upstream * out rulematching all; #default
+
+pinstance B upstream bp out blacklist table allways; #(u1)
+#pinstance B upstream bp in whitelist table {(*|*)}; #default (u2, u3)
+
+pinstance B upstream b1 out blacklist table piB_peering_ifs; #(u3_1)
+#pinstance b upstream b1 in whitelist table {(*|*)}; #default
+
+pinstance B downstream bp in blacklist table allways; #(d1)
+pinstance B downstream bp out blacklist table piB_upstreams; #(d2, d2_1, d3, d4)
+
+#pinstance B downstream b2 in whitelist table {(*|*)}; #default
+#pinstance B downstream b2 out whitelist table {(*|*)}; #default
diff --git a/external/routing/mcproxy/files/mcproxy.config b/external/routing/mcproxy/files/mcproxy.config
new file mode 100644
index 0000000..f028795
--- /dev/null
+++ b/external/routing/mcproxy/files/mcproxy.config
@@ -0,0 +1,239 @@
+# Use your own MCProxy config file
+config mcproxy 'mcproxy_file'
+ option disabled '1'
+ option respawn '1'
+ option file '/etc/mcproxy.conf'
+
+# Use OpenWrt UCI config
+config mcproxy 'mcproxy'
+ option disabled '1'
+ option respawn '1'
+ option protocol 'IGMPv3'
+
+###########################################
+
+# Simple configuration examples
+
+config instance
+ option disabled '1'
+ option name 'proxy1'
+ list upstream 'eth1'
+ list downstream 'eth0.2'
+
+config instance
+ option disabled '1'
+ option name 'proxy2'
+ list upstream 'eth0.2'
+ list downstream 'eth0.4'
+ list downstream 'br-lan'
+
+config instance
+ option disabled '1'
+ option name 'proxy3'
+ list upstream 'eth1.2'
+ list upstream 'eth1.4'
+ list downstream 'eth0.1'
+
+###########################################
+
+# Advanced configuration example
+
+config instance
+ option name 'A'
+ list upstream 'ap'
+ list upstream 'a1'
+ list downstream 'ap'
+ list downstream 'a2'
+
+config instance
+ option name 'B'
+ list upstream 'bp'
+ list upstream 'b1'
+ list downstream 'bp'
+ list downstream 'b2'
+
+config table
+ option name 'allways'
+ list entries '(*|*)'
+
+config table
+ option name 'piA_peering_ifs'
+ list entries 'ap(*|*)'
+
+config table
+ option name 'piA_upstreams'
+ list entries 'a1(*|*)'
+
+config table
+ option name 'piB_peering_ifs'
+ list entries 'bp(*|*)'
+
+config table
+ option name 'piB_upstreams'
+ list entries 'b1(*|*)'
+
+config behaviour
+ option instance 'A'
+ option section 'upstream'
+ option interface '*'
+ option direction 'in'
+ option rulematching 'mutex 10'
+
+config behaviour
+ option disabled '1'
+ option instance 'A'
+ option section 'upstream'
+ option interface '*'
+ option direction 'out'
+ option rulematching 'all'
+
+config behaviour
+ option instance 'A'
+ option section 'upstream'
+ option interface 'ap'
+ option direction 'out'
+ option table 'allways'
+
+config behaviour
+ option disabled '1'
+ option instance 'A'
+ option section 'upstream'
+ option interface 'ap'
+ option direction 'in'
+ option whitelist '1'
+ option table '{(*|*)}'
+
+config behaviour
+ option instance 'A'
+ option section 'upstream'
+ option interface 'a1'
+ option direction 'out'
+ option table 'piA_peering_ifs'
+
+config behaviour
+ option disabled '1'
+ option instance 'A'
+ option section 'upstream'
+ option interface 'a1'
+ option direction 'in'
+ option whitelist '1'
+ option table '{(*|*)}'
+
+config behaviour
+ option instance 'A'
+ option section 'downstream'
+ option interface 'ap'
+ option direction 'in'
+ option table 'allways'
+
+config behaviour
+ option instance 'A'
+ option section 'downstream'
+ option interface 'ap'
+ option direction 'out'
+ option table 'piA_upstreams'
+
+config behaviour
+ option disabled '1'
+ option instance 'A'
+ option section 'downstream'
+ option interface 'a2'
+ option direction 'in'
+ option whitelist '1'
+ option table '{(*|*)}'
+
+config behaviour
+ option disabled '1'
+ option instance 'A'
+ option section 'downstream'
+ option interface 'a2'
+ option direction 'out'
+ option whitelist '1'
+ option table '{(*|*)}'
+
+config behaviour
+ option instance 'B'
+ option section 'upstream'
+ option interface '*'
+ option direction 'in'
+ option rulematching 'mutex 10'
+
+config behaviour
+ option disabled '1'
+ option instance 'B'
+ option section 'upstream'
+ option interface '*'
+ option direction 'out'
+ option rulematching 'all'
+
+config behaviour
+ option instance 'B'
+ option section 'upstream'
+ option interface 'bp'
+ option direction 'out'
+ option table 'allways'
+
+config behaviour
+ option disabled '1'
+ option instance 'B'
+ option section 'upstream'
+ option interface 'bp'
+ option direction 'in'
+ option whitelist '1'
+ option table '{(*|*)}'
+
+config behaviour
+ option instance 'B'
+ option section 'upstream'
+ option interface 'b1'
+ option direction 'out'
+ option table 'piB_peering_ifs'
+
+config behaviour
+ option disabled '1'
+ option instance 'B'
+ option section 'upstream'
+ option interface 'b1'
+ option direction 'in'
+ option whitelist '1'
+ option table '{(*|*)}'
+
+config behaviour
+ option instance 'B'
+ option section 'downstream'
+ option interface 'bp'
+ option direction 'in'
+ option table 'allways'
+
+config behaviour
+ option instance 'B'
+ option section 'downstream'
+ option interface 'bp'
+ option direction 'out'
+ option table 'piB_upstreams'
+
+config behaviour
+ option disabled '1'
+ option instance 'B'
+ option section 'downstream'
+ option interface 'b2'
+ option direction 'in'
+ option whitelist '1'
+ option table '{(*|*)}'
+
+config behaviour
+ option disabled '1'
+ option instance 'B'
+ option section 'downstream'
+ option interface 'b2'
+ option direction 'out'
+ option whitelist '1'
+ option table '{(*|*)}'
+
+config blocks blocks
+ # mDNS
+ list entries '(*|239.255.255.0/24)'
+ # SSDP
+ list entries '(*|224.0.0.0/24)'
+ # SLP
+ list entries '(*|239.192.0.0/16)'
diff --git a/external/routing/mcproxy/files/mcproxy.init b/external/routing/mcproxy/files/mcproxy.init
new file mode 100644
index 0000000..60e4c87
--- /dev/null
+++ b/external/routing/mcproxy/files/mcproxy.init
@@ -0,0 +1,184 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2014-2015 OpenWrt.org
+
+START=99
+USE_PROCD=1
+
+mcproxy_handle_instances() {
+ local instance="$1"
+ local conf_file="$2"
+ local disabled
+ local pre=""
+ local name
+ local upstreams
+ local downstreams
+
+ config_get_bool disabled "$instance" 'disabled' '0'
+ config_get name "$instance" "name" "$instance"
+ config_get upstreams "$instance" "upstream"
+ config_get downstreams "$instance" "downstream"
+
+ if [ $disabled -eq 1 ]; then
+ pre="# "
+ fi
+
+ local str_up=""
+ if [ -n "$upstreams" ]; then
+ local upstream
+ for upstream in $upstreams; do
+ str_up="$str_up \"$upstream\""
+ done
+ fi
+
+ local str_down=""
+ if [ -n "$downstreams" ]; then
+ local downstream
+ for downstream in $downstreams; do
+ str_down="$str_down \"$downstream\""
+ done
+ fi
+
+ if [ ! -z $downstream ]; then
+ echo -e "${pre}pinstance ${name}:${str_up} ==>${str_down};\n" >> $conf_file
+ fi
+}
+
+# mcproxy_list_table <var> <section> <option>
+mcproxy_list_table() {
+ local val
+ local len
+ local _buffer
+ local c=1
+
+ config_get len "$2" "${3}_LENGTH"
+ [ -z "$len" ] && return 0
+ while [ $c -le "$len" ]; do
+ config_get val "$2" "${3}_ITEM$c"
+ append _buffer "\t${val}\n"
+ c="$(($c + 1))"
+ done
+
+ export "${1}=${_buffer}";
+}
+
+mcproxy_handle_tables() {
+ local table="$1"
+ local conf_file="$2"
+ local name
+ local entries
+
+ config_get name "$table" "name" ""
+ mcproxy_list_table entries "$table" "entries"
+
+ if [ ! -z $name ] && [ ! -z $table ]; then
+ echo -e "table $name {\n${entries}};\n" >> $conf_file
+ fi
+}
+
+mcproxy_handle_behaviour() {
+ local behaviour="$1"
+ local conf_file="$2"
+ local disabled
+ local pre=""
+ local instance
+ local section
+ local interface
+ local direction
+ local rulematching
+ local table
+
+ config_get_bool disabled "$behaviour" 'disabled' '0'
+ config_get instance "$behaviour" "instance"
+ config_get section "$behaviour" "section" "upstream"
+ config_get interface "$behaviour" "interface" "*"
+ config_get direction "$behaviour" "direction" "in"
+ config_get rulematching "$behaviour" "rulematching"
+ config_get table "$behaviour" "table"
+
+ if [ -z $instance ]; then
+ return 1
+ fi
+
+ local rule_table
+ if [ ! -z $rulematching ]; then
+ rule_table="rulematching $rulematching"
+ elif [ ! -z $table ]; then
+ local whitelist
+ local list
+
+ config_get_bool whitelist "$behaviour" 'whitelist' '0'
+ if [ $whitelist -eq 1 ]; then
+ list="whitelist"
+ else
+ list="blacklist"
+ fi
+
+ rule_table="$list table $table"
+ else
+ rule_table="rulematching all"
+ fi
+
+ if [ $disabled -eq 1 ]; then
+ pre="# "
+ fi
+
+ echo -e "${pre}pinstance $instance $section \"$interface\" $direction $rule_table;\n" >> $conf_file
+}
+
+mcproxy_network_trigger() {
+ procd_add_interface_trigger "interface.*" "$1" /etc/init.d/mcproxy restart
+}
+mcproxy_handle_network() {
+ local instance="$1"
+
+ config_list_foreach "$instance" upstream mcproxy_network_trigger
+ config_list_foreach "$instance" downstream mcproxy_network_trigger
+}
+
+start_instance() {
+ local cfg="$1"
+ local aux
+ local conf_file
+
+ config_get_bool aux "$cfg" 'disabled' '0'
+ [ "$aux" = 1 ] && return 1
+
+ config_get conf_file "$cfg" "file"
+ if [ ! -n "$conf_file" ]; then
+ mkdir -p /var/etc
+ conf_file="/var/etc/mcproxy_${cfg}.conf"
+
+ local protocol
+ config_get protocol "$cfg" "protocol" "IGMPv3"
+ echo -e "protocol ${protocol};\n" > $conf_file
+
+ config_foreach mcproxy_handle_instances instance $conf_file
+ config_foreach mcproxy_handle_tables table $conf_file
+ config_foreach mcproxy_handle_behaviour behaviour $conf_file
+ fi
+
+ procd_open_instance
+
+ procd_set_param command /usr/sbin/mcproxy
+ procd_append_param command -f $conf_file
+
+ config_get_bool aux "$cfg" 'respawn' '0'
+ [ "$aux" = 1 ] && procd_set_param respawn
+
+ procd_open_trigger
+ config_foreach mcproxy_handle_network instance
+ procd_close_trigger
+
+ procd_close_instance
+}
+
+service_triggers() {
+ procd_open_trigger
+ procd_add_config_trigger "config.change" "mcproxy" /etc/init.d/mcproxy restart
+ procd_close_trigger
+}
+
+start_service() {
+ config_load mcproxy
+ config_foreach start_instance mcproxy
+}
diff --git a/external/routing/mcproxy/patches/0001-add-cmake.patch b/external/routing/mcproxy/patches/0001-add-cmake.patch
new file mode 100644
index 0000000..c3978a5
--- /dev/null
+++ b/external/routing/mcproxy/patches/0001-add-cmake.patch
@@ -0,0 +1,54 @@
+--- /dev/null
++++ b/CMakeLists.txt
+@@ -0,0 +1,51 @@
++cmake_minimum_required(VERSION 2.8)
++
++# Project Definition
++project(mcproxy CXX)
++set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
++set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++11")
++add_definitions(-Wall -Wextra)
++include_directories(${CMAKE_SOURCE_DIR}/mcproxy)
++
++
++add_executable(mcproxy-bin mcproxy/src/main.cpp
++ mcproxy/src/hamcast_logging.cpp
++ #utils
++ mcproxy/src/utils/mc_socket.cpp
++ mcproxy/src/utils/addr_storage.cpp
++ mcproxy/src/utils/mroute_socket.cpp
++ mcproxy/src/utils/if_prop.cpp
++ mcproxy/src/utils/reverse_path_filter.cpp
++ #proxy
++ mcproxy/src/proxy/proxy.cpp
++ mcproxy/src/proxy/sender.cpp
++ mcproxy/src/proxy/receiver.cpp
++ mcproxy/src/proxy/mld_receiver.cpp
++ mcproxy/src/proxy/igmp_receiver.cpp
++ mcproxy/src/proxy/mld_sender.cpp
++ mcproxy/src/proxy/igmp_sender.cpp
++ mcproxy/src/proxy/proxy_instance.cpp
++ mcproxy/src/proxy/routing.cpp
++ mcproxy/src/proxy/worker.cpp
++ mcproxy/src/proxy/timing.cpp
++ mcproxy/src/proxy/check_if.cpp
++ mcproxy/src/proxy/check_kernel.cpp
++ mcproxy/src/proxy/membership_db.cpp
++ mcproxy/src/proxy/querier.cpp
++ mcproxy/src/proxy/timers_values.cpp
++ mcproxy/src/proxy/interfaces.cpp
++ mcproxy/src/proxy/def.cpp
++ mcproxy/src/proxy/simple_mc_proxy_routing.cpp
++ mcproxy/src/proxy/simple_routing_data.cpp
++ #parser
++ mcproxy/src/parser/scanner.cpp
++ mcproxy/src/parser/token.cpp
++ mcproxy/src/parser/configuration.cpp
++ mcproxy/src/parser/parser.cpp
++ mcproxy/src/parser/interface.cpp
++)
++target_link_libraries(mcproxy-bin pthread)
++
++# Installation
++install(TARGETS mcproxy-bin DESTINATION bin/)
++
diff --git a/external/routing/mcproxy/patches/0002-rm-stoi.patch b/external/routing/mcproxy/patches/0002-rm-stoi.patch
new file mode 100644
index 0000000..a25c9fb
--- /dev/null
+++ b/external/routing/mcproxy/patches/0002-rm-stoi.patch
@@ -0,0 +1,40 @@
+--- a/mcproxy/src/parser/parser.cpp
++++ b/mcproxy/src/parser/parser.cpp
+@@ -126,7 +126,7 @@ void parser::parse_instance_definition(i
+ get_next_token();
+ if (m_current_token.get_type() == TT_STRING) {
+ try {
+- table_number = std::stoi(m_current_token.get_string());
++ table_number = atoi(m_current_token.get_string().c_str());
+ user_selected_table_number = true;
+ } catch (std::logic_error e) {
+ HC_LOG_ERROR("failed to parse line " << m_current_line << " table number: " << table_number << " is not a number");
+@@ -299,7 +299,7 @@ std::unique_ptr<addr_match> parser::pars
+ get_next_token();
+ if (m_current_token.get_type() == TT_STRING) {
+ try {
+- unsigned int prefix = std::stoi(m_current_token.get_string());
++ unsigned int prefix = atoi(m_current_token.get_string().c_str());
+ if (prefix > 128) {
+ throw;
+ }
+@@ -561,7 +561,7 @@ void parser::parse_interface_rule_match_
+ get_next_token();
+ if (m_current_token.get_type() == TT_STRING) {
+ try {
+- int tmp_timeout = std::stoi(m_current_token.get_string());
++ int tmp_timeout = atoi(m_current_token.get_string().c_str());
+ timeout = std::chrono::milliseconds(tmp_timeout);
+ } catch (...) {
+ error_notification();
+--- a/mcproxy/src/utils/addr_storage.cpp
++++ b/mcproxy/src/utils/addr_storage.cpp
+@@ -298,7 +298,7 @@ addr_storage& addr_storage::set_port(uin
+
+ addr_storage& addr_storage::set_port(const std::string& port)
+ {
+- set_port(std::stoi(port.c_str()));
++ set_port(atoi(port.c_str()));
+ return *this;
+ }
+
diff --git a/external/routing/mcproxy/patches/0003-add-sourcefilter.patch b/external/routing/mcproxy/patches/0003-add-sourcefilter.patch
new file mode 100644
index 0000000..a47fcae
--- /dev/null
+++ b/external/routing/mcproxy/patches/0003-add-sourcefilter.patch
@@ -0,0 +1,181 @@
+--- a/mcproxy/src/utils/mc_socket.cpp
++++ b/mcproxy/src/utils/mc_socket.cpp
+@@ -37,6 +37,10 @@
+ #include <numeric>
+ #include <unistd.h>
+
++#if !defined(__GLIBC__) || defined(__UCLIBC__)
++#include "sourcefilter.cpp"
++#endif /* __GLIBC__ */
++
+ std::string ipAddrResolver(std::string ipAddr)
+ {
+ std::string str[][2] = {
+--- /dev/null
++++ b/mcproxy/src/utils/sourcefilter.cpp
+@@ -0,0 +1,165 @@
++/* Get source filter. Linux version.
++ Copyright (C) 2004-2014 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <assert.h>
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include <stdint.h>
++#include <netinet/in.h>
++#include <netpacket/packet.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++
++static const struct
++{
++ int sol;
++ int af;
++ socklen_t size;
++} sol_map[] =
++ {
++ /* Sort the array according to importance of the protocols. Add
++ more protocols when they become available. */
++ { SOL_IP, AF_INET, sizeof (struct sockaddr_in) },
++ { SOL_IPV6, AF_INET6, sizeof (struct sockaddr_in6) },
++ { SOL_PACKET, AF_PACKET, sizeof (struct sockaddr_ll) }
++ };
++#define NSOL_MAP (sizeof (sol_map) / sizeof (sol_map[0]))
++
++
++/* Try to determine the socket level value. Ideally both side and
++ family are set. But sometimes only the size is correct and the
++ family value might be bogus. Loop over the array entries and look
++ for a perfect match or the first match based on size. */
++static int
++__get_sol (int af, socklen_t len)
++{
++ int first_size_sol = -1;
++
++ for (size_t cnt = 0; cnt < NSOL_MAP; ++cnt)
++ {
++ /* Just a test so that we make sure the special value used to
++ signal the "we have so far no socket level value" is OK. */
++ assert (sol_map[cnt].sol != -1);
++
++ if (len == sol_map[cnt].size)
++ {
++ /* The size matches, which is a requirement. If the family
++ matches, too, we have a winner. Otherwise we remember the
++ socket level value for this protocol if it is the first
++ match. */
++ if (af == sol_map[cnt].af)
++ /* Bingo! */
++ return sol_map[cnt].sol;
++
++ if (first_size_sol == -1)
++ first_size_sol = sol_map[cnt].sol;
++ }
++ }
++
++ return first_size_sol;
++}
++
++
++int
++getsourcefilter (int s, uint32_t interface, const struct sockaddr *group,
++ socklen_t grouplen, uint32_t *fmode, uint32_t *numsrc,
++ struct sockaddr_storage *slist)
++{
++ /* We have to create an struct ip_msfilter object which we can pass
++ to the kernel. */
++ socklen_t needed = GROUP_FILTER_SIZE (*numsrc);
++ struct group_filter *gf;
++ gf = (struct group_filter *) malloc (needed);
++ if (gf == NULL)
++ return -1;
++
++ gf->gf_interface = interface;
++ memcpy (&gf->gf_group, group, grouplen);
++ gf->gf_numsrc = *numsrc;
++
++ /* We need to provide the appropriate socket level value. */
++ int result;
++ int sol = __get_sol (group->sa_family, grouplen);
++ if (sol == -1)
++ {
++ errno = EINVAL;
++ result = -1;
++ }
++ else
++ {
++ result = getsockopt (s, sol, MCAST_MSFILTER, gf, &needed);
++
++ /* If successful, copy the results to the places the caller wants
++ them in. */
++ if (result == 0)
++ {
++ *fmode = gf->gf_fmode;
++ memcpy (slist, gf->gf_slist,
++ MIN (*numsrc, gf->gf_numsrc)
++ * sizeof (struct sockaddr_storage));
++ *numsrc = gf->gf_numsrc;
++ }
++ }
++
++ int save_errno = errno;
++ free (gf);
++ errno = save_errno;
++
++ return result;
++}
++
++
++int
++setsourcefilter (int s, uint32_t interface, const struct sockaddr *group,
++ socklen_t grouplen, uint32_t fmode, uint32_t numsrc,
++ const struct sockaddr_storage *slist)
++{
++ /* We have to create an struct ip_msfilter object which we can pass
++ to the kernel. */
++ size_t needed = GROUP_FILTER_SIZE (numsrc);
++
++ struct group_filter *gf;
++ gf = (struct group_filter *) malloc (needed);
++ if (gf == NULL)
++ return -1;
++
++ gf->gf_interface = interface;
++ memcpy (&gf->gf_group, group, grouplen);
++ gf->gf_fmode = fmode;
++ gf->gf_numsrc = numsrc;
++ memcpy (gf->gf_slist, slist, numsrc * sizeof (struct sockaddr_storage));
++
++ /* We need to provide the appropriate socket level value. */
++ int result;
++ int sol = __get_sol (group->sa_family, grouplen);
++ if (sol == -1)
++ {
++ errno = EINVAL;
++ result = -1;
++ }
++ else
++ result = setsockopt (s, sol, MCAST_MSFILTER, gf, needed);
++
++ int save_errno = errno;
++ free (gf);
++ errno = save_errno;
++
++ return result;
++}
diff --git a/external/routing/mcproxy/patches/0004-add-defs.patch b/external/routing/mcproxy/patches/0004-add-defs.patch
new file mode 100644
index 0000000..19feb88
--- /dev/null
+++ b/external/routing/mcproxy/patches/0004-add-defs.patch
@@ -0,0 +1,11 @@
+--- a/mcproxy/src/utils/mc_socket.cpp
++++ b/mcproxy/src/utils/mc_socket.cpp
+@@ -38,6 +38,8 @@
+ #include <unistd.h>
+
+ #if !defined(__GLIBC__) || defined(__UCLIBC__)
++#define IP_MULTICAST_ALL 49
++
+ #include "sourcefilter.cpp"
+ #endif /* __GLIBC__ */
+
diff --git a/external/routing/mcproxy/patches/0005-fix-match-filter-calls.patch b/external/routing/mcproxy/patches/0005-fix-match-filter-calls.patch
new file mode 100644
index 0000000..c6956e0
--- /dev/null
+++ b/external/routing/mcproxy/patches/0005-fix-match-filter-calls.patch
@@ -0,0 +1,46 @@
+--- a/mcproxy/src/proxy/simple_mc_proxy_routing.cpp
++++ b/mcproxy/src/proxy/simple_mc_proxy_routing.cpp
+@@ -118,13 +118,13 @@ void interface_memberships::process_upst
+ for (auto source_it = cs.first.m_source_list.begin(); source_it != cs.first.m_source_list.end();) {
+
+ //downstream out
+- if (!cs.second->match_output_filter(interfaces::get_if_name(upstr_e.m_if_index), gaddr, source_it->saddr)) {
++ if (!cs.second->match_output_filter(interfaces::get_if_name(upstr_e.m_if_index), source_it->saddr, gaddr)) {
+ source_it = cs.first.m_source_list.erase(source_it);
+ continue;
+ }
+
+ //upstream in
+- if (!upstr_e.m_interface->match_input_filter(interfaces::get_if_name(upstr_e.m_if_index), gaddr, source_it->saddr)) {
++ if (!upstr_e.m_interface->match_input_filter(interfaces::get_if_name(upstr_e.m_if_index), source_it->saddr, gaddr)) {
+ tmp_sstate.m_source_list.insert(*source_it);
+ source_it = cs.first.m_source_list.erase(source_it);
+ continue;
+@@ -175,13 +175,13 @@ void interface_memberships::process_upst
+ for (auto source_it = cs_it->first.m_source_list.begin(); source_it != cs_it->first.m_source_list.end();) {
+
+ //downstream out
+- if (!cs_it->second->match_output_filter(interfaces::get_if_name(upstr_e.m_if_index), gaddr, source_it->saddr)) {
++ if (!cs_it->second->match_output_filter(interfaces::get_if_name(upstr_e.m_if_index), source_it->saddr, gaddr)) {
+ ++source_it;
+ continue;
+ }
+
+ //upstream in
+- if (!upstr_e.m_interface->match_input_filter(interfaces::get_if_name(upstr_e.m_if_index), gaddr, source_it->saddr)) {
++ if (!upstr_e.m_interface->match_input_filter(interfaces::get_if_name(upstr_e.m_if_index), source_it->saddr, gaddr)) {
+ ++source_it;
+ continue;
+ }
+@@ -619,9 +619,9 @@ bool simple_mc_proxy_routing::check_inte
+ std::string input_if_index_name = interfaces::get_if_name(input_if_index);
+ if (!input_if_index_name.empty()) {
+ if (interface_direction == ID_IN) {
+- return interf->match_input_filter(input_if_index_name, gaddr, saddr);
++ return interf->match_input_filter(input_if_index_name, saddr, gaddr);
+ } else if (interface_direction == ID_OUT) {
+- return interf->match_output_filter(input_if_index_name, gaddr, saddr);
++ return interf->match_output_filter(input_if_index_name, saddr, gaddr);
+ } else {
+ HC_LOG_ERROR("unkown interface direction");
+ return false;
diff --git a/external/routing/mcproxy/patches/0006-block-ingress.patch b/external/routing/mcproxy/patches/0006-block-ingress.patch
new file mode 100644
index 0000000..730c6ce
--- /dev/null
+++ b/external/routing/mcproxy/patches/0006-block-ingress.patch
@@ -0,0 +1,88 @@
+--- a/mcproxy/src/proxy/proxy_instance.cpp
++++ b/mcproxy/src/proxy/proxy_instance.cpp
+@@ -171,6 +171,9 @@ void proxy_instance::worker_thread()
+ HC_LOG_TRACE("");
+ while (m_running) {
+ auto msg = m_job_queue.dequeue();
++
++ HC_LOG_DEBUG("Proxy Message: " << msg->get_message_type_name(msg->get_type()) );
++
+ switch (msg->get_type()) {
+ case proxy_msg::TEST_MSG:
+ (*msg)();
+@@ -193,25 +196,66 @@ void proxy_instance::worker_thread()
+ }
+ break;
+ case proxy_msg::GROUP_RECORD_MSG: {
+- auto r = std::static_pointer_cast<group_record_msg>(msg);
++ auto gr = std::static_pointer_cast<group_record_msg>(msg);
+
+ if (m_in_debug_testing_mode) {
+ std::cout << "!!--ACTION: receive record" << std::endl;
+- std::cout << *r << std::endl;
++ std::cout << *gr << std::endl;
+ std::cout << std::endl;
+ }
+
+- auto it = m_downstreams.find(r->get_if_index());
++ auto slist = gr->get_slist();
++ addr_storage saddr;
++ if (slist.empty()) {
++ saddr = "0.0.0.0";
++ } else {
++ saddr = slist.begin()->saddr;
++ }
++ auto it = m_downstreams.find(gr->get_if_index());
+ if (it != std::end(m_downstreams)) {
+- it->second.m_querier->receive_record(msg);
++ // Check for input filters
++ if (!it->second.m_interface->match_input_filter(interfaces::get_if_name(gr->get_if_index()), saddr, gr->get_gaddr()))
++ {
++ HC_LOG_DEBUG("group report " << gr->get_gaddr() << " filtered");
++ }
++ else
++ {
++ it->second.m_querier->receive_record(msg);
++ }
+ } else {
+- HC_LOG_DEBUG("failed to find querier of interface: " << interfaces::get_if_name(std::static_pointer_cast<timer_msg>(msg)->get_if_index()));
++ HC_LOG_DEBUG("failed to find querier of interface: " << interfaces::get_if_name( gr->get_if_index() ));
+ }
+- }
++ }
++ break;
++ case proxy_msg::NEW_SOURCE_MSG: {
++ auto sm = std::static_pointer_cast<new_source_msg>(msg);
++ // Find the interface
++ std::shared_ptr<interface> interf;
++ auto it = m_downstreams.find(sm->get_if_index());
++ if (it != std::end(m_downstreams)) {
++ interf = it->second.m_interface;
++ } else {
++ for (auto & e : m_upstreams) {
++ if (e.m_if_index == sm->get_if_index()) {
++ interf = e.m_interface;
++ break;
++ }
++ }
++ }
++ if ( !interf )
++ {
++ HC_LOG_DEBUG("failed to find interface: " << interfaces::get_if_name( sm->get_if_index() ) << " for Source message " << sm->get_saddr() << " | " << sm->get_gaddr() );
++ break;
++ }
++ // Check for input filters
++ if (!interf->match_input_filter(interfaces::get_if_name(sm->get_if_index()), sm->get_saddr(), sm->get_gaddr()))
++ {
++ HC_LOG_DEBUG("source " << sm->get_saddr() << " | " << sm->get_gaddr() << " filtered");
++ } else {
++ m_routing_management->event_new_source(msg);
++ }
++ }
+ break;
+- case proxy_msg::NEW_SOURCE_MSG:
+- m_routing_management->event_new_source(msg);
+- break;
+ case proxy_msg::NEW_SOURCE_TIMER_MSG:
+ m_routing_management->timer_triggerd_maintain_routing_table(msg);
+ break;
diff --git a/external/routing/mcproxy/patches/0007-igmpv2-queries.patch b/external/routing/mcproxy/patches/0007-igmpv2-queries.patch
new file mode 100644
index 0000000..005b56d
--- /dev/null
+++ b/external/routing/mcproxy/patches/0007-igmpv2-queries.patch
@@ -0,0 +1,116 @@
+--- a/mcproxy/include/proxy/igmp_sender.hpp
++++ b/mcproxy/include/proxy/igmp_sender.hpp
+@@ -37,9 +37,10 @@ class igmp_sender : public sender
+ {
+ private:
+ bool send_igmpv3_query(unsigned int if_index, const timers_values& tv, const addr_storage& gaddr, bool s_flag, const source_list<source>& slist) const;
++ bool send_igmpv2_query(unsigned int if_index, const timers_values& tv, const addr_storage& gaddr ) const;
+
+ public:
+- igmp_sender(const std::shared_ptr<const interfaces>& interfaces);
++ igmp_sender(const std::shared_ptr<const interfaces>& interfaces, const group_mem_protocol gmp);
+
+ bool send_record(unsigned int if_index, mc_filter filter_mode, const addr_storage& gaddr, const source_list<source>& slist) const override;
+
+--- a/mcproxy/src/proxy/igmp_sender.cpp
++++ b/mcproxy/src/proxy/igmp_sender.cpp
+@@ -32,7 +32,7 @@
+
+ #include <memory>
+
+-igmp_sender::igmp_sender(const std::shared_ptr<const interfaces>& interfaces): sender(interfaces, IGMPv3)
++igmp_sender::igmp_sender(const std::shared_ptr<const interfaces>& interfaces, const group_mem_protocol gmp): sender(interfaces, gmp)
+ {
+ HC_LOG_TRACE("");
+
+@@ -119,10 +119,79 @@ bool igmp_sender::send_mc_addr_and_src_s
+ return rc;
+ }
+
++bool igmp_sender::send_igmpv2_query(unsigned int if_index, const timers_values& tv, const addr_storage& gaddr ) const
++{
++ HC_LOG_TRACE("");
++
++ std::unique_ptr<unsigned char[]> packet;
++ unsigned int size;
++
++ size = sizeof(ip) + sizeof(router_alert_option) + sizeof(igmp);
++ packet.reset(new unsigned char[size]);
++
++ addr_storage dst_addr;
++
++ if (gaddr == addr_storage(AF_INET)) { //is general query
++ dst_addr = IPV4_ALL_HOST_ADDR;
++ } else {
++ dst_addr = gaddr;
++ }
++
++ //-------------------------------------------------------------------
++ //fill ip header
++ ip* ip_hdr = reinterpret_cast<ip*>(packet.get());
++
++ ip_hdr->ip_v = 4;
++ ip_hdr->ip_hl = (sizeof(ip) + sizeof(router_alert_option)) / 4;
++ ip_hdr->ip_tos = 0;
++ ip_hdr->ip_len = htons(size);
++ ip_hdr->ip_id = 0;
++ ip_hdr->ip_off = htons(0 | IP_DF); //dont fragment flag
++ ip_hdr->ip_ttl = 1;
++ ip_hdr->ip_p = IPPROTO_IGMP;
++ ip_hdr->ip_sum = 0;
++ ip_hdr->ip_src = m_interfaces->get_saddr(interfaces::get_if_name(if_index)).get_in_addr();
++ ip_hdr->ip_dst = dst_addr.get_in_addr();
++
++ //-------------------------------------------------------------------
++ //fill router_alert_option header
++ router_alert_option* ra_hdr = reinterpret_cast<router_alert_option*>(reinterpret_cast<unsigned char*>(ip_hdr) + sizeof(ip));
++ *ra_hdr = router_alert_option();
++
++ ip_hdr->ip_sum = m_sock.calc_checksum(reinterpret_cast<unsigned char*>(ip_hdr), sizeof(ip) + sizeof(router_alert_option));
++
++ //-------------------------------------------------------------------
++ //fill igmpv3 query
++ igmp* query = reinterpret_cast<igmp*>(reinterpret_cast<unsigned char*>(ra_hdr) + sizeof(router_alert_option));
++
++ query->igmp_type = IGMP_MEMBERSHIP_QUERY;
++
++ if (gaddr == addr_storage(AF_INET)) { //general query
++ query->igmp_code = tv.maxrespi_to_maxrespc_igmpv3(tv.get_query_response_interval());
++ } else {
++ query->igmp_code = tv.maxrespi_to_maxrespc_igmpv3(tv.get_last_listener_query_time());
++ }
++
++ query->igmp_cksum = 0;
++ query->igmp_group = gaddr.get_in_addr();
++
++ query->igmp_cksum = m_sock.calc_checksum(reinterpret_cast<unsigned char*>(query), (sizeof(igmp) ));
++
++ if (!m_sock.choose_if(if_index)) {
++ return false;
++ }
++
++ return m_sock.send_packet(dst_addr, reinterpret_cast<unsigned char*>(ip_hdr), size);
++}
++
+ bool igmp_sender::send_igmpv3_query(unsigned int if_index, const timers_values& tv, const addr_storage& gaddr, bool s_flag, const source_list<source>& slist) const
+ {
+ HC_LOG_TRACE("");
+
++ if ( (m_group_mem_protocol & IGMPv3) == 0 ) {
++ return send_igmpv2_query( if_index, tv, gaddr );
++ }
++
+ std::unique_ptr<unsigned char[]> packet;
+ unsigned int size;
+
+--- a/mcproxy/src/proxy/proxy_instance.cpp
++++ b/mcproxy/src/proxy/proxy_instance.cpp
+@@ -119,7 +119,7 @@ bool proxy_instance::init_sender()
+ {
+ HC_LOG_TRACE("");
+ if (is_IPv4(m_group_mem_protocol)) {
+- m_sender = std::make_shared<igmp_sender>(m_interfaces);
++ m_sender = std::make_shared<igmp_sender>(m_interfaces, m_group_mem_protocol );
+ } else if (is_IPv6(m_group_mem_protocol)) {
+ m_sender = std::make_shared<mld_sender>(m_interfaces);
+ } else {