mcproxy: add igmpV2 reply support

mcproxy has no way to send an IGMPv2 query today. If you force IGMPv2 (by
setting the protocol in the mcproxy config and setting the force_igmp_version
flag on all interfaces) the bridge will send v2 queries but if mcproxy takes
over as the querier it will send v3 queries. The patch below adds support for
sending v2 queries so everyone stays in sync:

Signed-off-by: Sukru Senli <sukru.senli@iopsys.eu>
Signed-off-by: Chad Monroe <chad.monroe@smartrg.com>
Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
John Crispin 2019-06-05 20:33:42 +02:00
parent 490971e8e5
commit a56d996b94
3 changed files with 167 additions and 65 deletions

View File

@ -230,7 +230,7 @@ config behaviour
option whitelist '1'
option table '{(*|*)}'
config blocks
config blocks blocks
# mDNS
list entries '(*|239.255.255.0/24)'
# SSDP

View File

@ -1,25 +1,23 @@
--- a/mcproxy/src/proxy/proxy_instance.cpp
+++ b/mcproxy/src/proxy/proxy_instance.cpp
Index: mcproxy-2017-08-24-93b5ace42268160ebbfff4c61818fb15fa2d9b99/mcproxy/src/proxy/proxy_instance.cpp
===================================================================
--- mcproxy-2017-08-24-93b5ace42268160ebbfff4c61818fb15fa2d9b99.orig/mcproxy/src/proxy/proxy_instance.cpp
+++ mcproxy-2017-08-24-93b5ace42268160ebbfff4c61818fb15fa2d9b99/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()) );
+ HC_LOG_DEBUG("Proxy Message: " << msg->get_message_type_name(msg->get_type()) );
+
switch (msg->get_type()) {
case proxy_msg::TEST_MSG:
(*msg)();
@@ -190,28 +193,80 @@ void proxy_instance::worker_thread()
} else {
HC_LOG_DEBUG("failed to find querier of interface: " << interfaces::get_if_name(std::static_pointer_cast<timer_msg>(msg)->get_if_index()));
}
- }
+ }
@@ -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);
+ auto gr = std::static_pointer_cast<group_record_msg>(msg);
if (m_in_debug_testing_mode) {
std::cout << "!!--ACTION: receive record" << std::endl;
@ -29,31 +27,25 @@
}
- 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 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);
+ }
+ // 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() ));
@ -62,37 +54,32 @@
+ }
+ 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);
+ }
+ 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:
@ -101,4 +88,3 @@
case proxy_msg::NEW_SOURCE_TIMER_MSG:
m_routing_management->timer_triggerd_maintain_routing_table(msg);
break;
return false;

View File

@ -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 {