From a56d996b94682c90729ad9b561168635b857649c Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 5 Jun 2019 20:33:42 +0200 Subject: [PATCH] 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 Signed-off-by: Chad Monroe Signed-off-by: John Crispin --- mcproxy/files/mcproxy.config | 2 +- mcproxy/patches/0006-block-ingress.patch | 114 ++++++++++----------- mcproxy/patches/0007-igmpv2-queries.patch | 116 ++++++++++++++++++++++ 3 files changed, 167 insertions(+), 65 deletions(-) create mode 100644 mcproxy/patches/0007-igmpv2-queries.patch diff --git a/mcproxy/files/mcproxy.config b/mcproxy/files/mcproxy.config index e80b602..f028795 100644 --- a/mcproxy/files/mcproxy.config +++ b/mcproxy/files/mcproxy.config @@ -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 diff --git a/mcproxy/patches/0006-block-ingress.patch b/mcproxy/patches/0006-block-ingress.patch index c8bcdb3..5998741 100644 --- a/mcproxy/patches/0006-block-ingress.patch +++ b/mcproxy/patches/0006-block-ingress.patch @@ -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(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(msg); -+ auto gr = std::static_pointer_cast(msg); ++ auto gr = std::static_pointer_cast(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(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(msg); -+ // Find the interface -+ std::shared_ptr 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(msg); ++ // Find the interface ++ std::shared_ptr 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; diff --git a/mcproxy/patches/0007-igmpv2-queries.patch b/mcproxy/patches/0007-igmpv2-queries.patch new file mode 100644 index 0000000..005b56d --- /dev/null +++ b/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& 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& interfaces); ++ igmp_sender(const std::shared_ptr& interfaces, const group_mem_protocol gmp); + + bool send_record(unsigned int if_index, mc_filter filter_mode, const addr_storage& gaddr, const source_list& slist) const override; + +--- a/mcproxy/src/proxy/igmp_sender.cpp ++++ b/mcproxy/src/proxy/igmp_sender.cpp +@@ -32,7 +32,7 @@ + + #include + +-igmp_sender::igmp_sender(const std::shared_ptr& interfaces): sender(interfaces, IGMPv3) ++igmp_sender::igmp_sender(const std::shared_ptr& 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 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(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(reinterpret_cast(ip_hdr) + sizeof(ip)); ++ *ra_hdr = router_alert_option(); ++ ++ ip_hdr->ip_sum = m_sock.calc_checksum(reinterpret_cast(ip_hdr), sizeof(ip) + sizeof(router_alert_option)); ++ ++ //------------------------------------------------------------------- ++ //fill igmpv3 query ++ igmp* query = reinterpret_cast(reinterpret_cast(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(query), (sizeof(igmp) )); ++ ++ if (!m_sock.choose_if(if_index)) { ++ return false; ++ } ++ ++ return m_sock.send_packet(dst_addr, reinterpret_cast(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& slist) const + { + HC_LOG_TRACE(""); + ++ if ( (m_group_mem_protocol & IGMPv3) == 0 ) { ++ return send_igmpv2_query( if_index, tv, gaddr ); ++ } ++ + std::unique_ptr 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(m_interfaces); ++ m_sender = std::make_shared(m_interfaces, m_group_mem_protocol ); + } else if (is_IPv6(m_group_mem_protocol)) { + m_sender = std::make_shared(m_interfaces); + } else {