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 {