back to topotato report
topotato coverage report
Current view: top level - pimd - pim_igmpv2.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 0 91 0.0 %
Date: 2023-02-24 14:41:08 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /*
       2             :  * PIM for Quagga
       3             :  * Copyright (C) 2016 Cumulus Networks, Inc.
       4             :  * Daniel Walton
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 2 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include "zebra.h"
      22             : 
      23             : #include "pimd.h"
      24             : #include "pim_instance.h"
      25             : #include "pim_igmp.h"
      26             : #include "pim_igmpv2.h"
      27             : #include "pim_igmpv3.h"
      28             : #include "pim_ssm.h"
      29             : #include "pim_str.h"
      30             : #include "pim_time.h"
      31             : #include "pim_util.h"
      32             : 
      33             : 
      34           0 : static void on_trace(const char *label, struct interface *ifp,
      35             :                      struct in_addr from)
      36             : {
      37           0 :         if (PIM_DEBUG_GM_TRACE) {
      38           0 :                 char from_str[INET_ADDRSTRLEN];
      39           0 :                 pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
      40           0 :                 zlog_debug("%s: from %s on %s", label, from_str, ifp->name);
      41             :         }
      42           0 : }
      43             : 
      44           0 : void igmp_v2_send_query(struct gm_group *group, int fd, const char *ifname,
      45             :                         char *query_buf, struct in_addr dst_addr,
      46             :                         struct in_addr group_addr,
      47             :                         int query_max_response_time_dsec)
      48             : {
      49           0 :         ssize_t msg_size = 8;
      50           0 :         uint8_t max_resp_code;
      51           0 :         ssize_t sent;
      52           0 :         struct sockaddr_in to;
      53           0 :         socklen_t tolen;
      54           0 :         uint16_t checksum;
      55             : 
      56             :         /* max_resp_code must be non-zero else this will look like an IGMP v1
      57             :          * query */
      58             :         /* RFC 2236: 2.2. , v2's is equal to it */
      59           0 :         max_resp_code = query_max_response_time_dsec;
      60           0 :         assert(max_resp_code > 0);
      61             : 
      62           0 :         query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY;
      63           0 :         query_buf[1] = max_resp_code;
      64           0 :         *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) =
      65             :                 0; /* for computing checksum */
      66           0 :         memcpy(query_buf + 4, &group_addr, sizeof(struct in_addr));
      67             : 
      68           0 :         checksum = in_cksum(query_buf, msg_size);
      69           0 :         *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = checksum;
      70             : 
      71           0 :         if (PIM_DEBUG_GM_PACKETS) {
      72           0 :                 char dst_str[INET_ADDRSTRLEN];
      73           0 :                 char group_str[INET_ADDRSTRLEN];
      74           0 :                 pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
      75           0 :                 pim_inet4_dump("<group?>", group_addr, group_str,
      76             :                                sizeof(group_str));
      77           0 :                 zlog_debug("Send IGMPv2 QUERY to %s on %s for group %s",
      78             :                            dst_str, ifname, group_str);
      79             :         }
      80             : 
      81           0 :         memset(&to, 0, sizeof(to));
      82           0 :         to.sin_family = AF_INET;
      83           0 :         to.sin_addr = dst_addr;
      84           0 :         tolen = sizeof(to);
      85             : 
      86           0 :         sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT,
      87             :                       (struct sockaddr *)&to, tolen);
      88           0 :         if (sent != (ssize_t)msg_size) {
      89           0 :                 char dst_str[INET_ADDRSTRLEN];
      90           0 :                 char group_str[INET_ADDRSTRLEN];
      91           0 :                 pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
      92           0 :                 pim_inet4_dump("<group?>", group_addr, group_str,
      93             :                                sizeof(group_str));
      94           0 :                 if (sent < 0) {
      95           0 :                         zlog_warn(
      96             :                                 "Send IGMPv2 QUERY failed due to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
      97             :                                 dst_str, ifname, group_str, msg_size, errno,
      98             :                                 safe_strerror(errno));
      99             :                 } else {
     100           0 :                         zlog_warn(
     101             :                                 "Send IGMPv2 QUERY failed due to %s on %s: group=%s msg_size=%zd: sent=%zd",
     102             :                                 dst_str, ifname, group_str, msg_size, sent);
     103             :                 }
     104           0 :                 return;
     105             :         }
     106             : }
     107             : 
     108           0 : int igmp_v2_recv_report(struct gm_sock *igmp, struct in_addr from,
     109             :                         const char *from_str, char *igmp_msg, int igmp_msg_len)
     110             : {
     111           0 :         struct interface *ifp = igmp->interface;
     112           0 :         struct in_addr group_addr;
     113           0 :         struct pim_interface *pim_ifp;
     114           0 :         char group_str[INET_ADDRSTRLEN];
     115             : 
     116           0 :         on_trace(__func__, igmp->interface, from);
     117             : 
     118           0 :         pim_ifp = ifp->info;
     119             : 
     120           0 :         if (igmp->mtrace_only)
     121             :                 return 0;
     122             : 
     123           0 :         if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
     124           0 :                 if (PIM_DEBUG_GM_PACKETS)
     125           0 :                         zlog_debug(
     126             :                                 "Recv IGMPv2 REPORT from %s on %s: size=%d other than correct=%d",
     127             :                                 from_str, ifp->name, igmp_msg_len,
     128             :                                 IGMP_V12_MSG_SIZE);
     129             :         }
     130             : 
     131           0 :         if (igmp_validate_checksum(igmp_msg, igmp_msg_len) == -1) {
     132           0 :                 zlog_warn(
     133             :                         "Recv IGMPv2 REPORT from %s on %s: size=%d with invalid checksum",
     134             :                         from_str, ifp->name, igmp_msg_len);
     135           0 :                 return -1;
     136             :         }
     137             : 
     138             :         /* Collecting IGMP Rx stats */
     139           0 :         igmp->igmp_stats.report_v2++;
     140             : 
     141           0 :         memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
     142             : 
     143           0 :         if (PIM_DEBUG_GM_PACKETS) {
     144           0 :                 pim_inet4_dump("<dst?>", group_addr, group_str,
     145             :                                sizeof(group_str));
     146           0 :                 zlog_debug("Recv IGMPv2 REPORT from %s on %s for %s", from_str,
     147             :                            ifp->name, group_str);
     148             :         }
     149             : 
     150             :         /*
     151             :          * RFC 4604
     152             :          * section 2.2.1
     153             :          * EXCLUDE mode does not apply to SSM addresses, and an SSM-aware router
     154             :          * will ignore MODE_IS_EXCLUDE and CHANGE_TO_EXCLUDE_MODE requests in
     155             :          * the SSM range.
     156             :          */
     157           0 :         if (pim_is_grp_ssm(pim_ifp->pim, group_addr)) {
     158           0 :                 if (PIM_DEBUG_GM_PACKETS) {
     159           0 :                         zlog_debug(
     160             :                                 "Ignoring IGMPv2 group record %pI4 from %s on %s exclude mode in SSM range",
     161             :                                 &group_addr.s_addr, from_str, ifp->name);
     162             :                 }
     163           0 :                 return -1;
     164             :         }
     165             : 
     166             : 
     167             :         /*
     168             :          * RFC 3376
     169             :          * 7.3.2. In the Presence of Older Version Group Members
     170             :          *
     171             :          * When Group Compatibility Mode is IGMPv2, a router internally
     172             :          * translates the following IGMPv2 messages for that group to their
     173             :          * IGMPv3 equivalents:
     174             :          *
     175             :          * IGMPv2 Message                IGMPv3 Equivalent
     176             :          * --------------                -----------------
     177             :          * Report                        IS_EX( {} )
     178             :          * Leave                         TO_IN( {} )
     179             :          */
     180           0 :         igmpv3_report_isex(igmp, from, group_addr, 0, NULL, 1);
     181             : 
     182           0 :         return 0;
     183             : }
     184             : 
     185           0 : int igmp_v2_recv_leave(struct gm_sock *igmp, struct ip *ip_hdr,
     186             :                        const char *from_str, char *igmp_msg, int igmp_msg_len)
     187             : {
     188           0 :         struct interface *ifp = igmp->interface;
     189           0 :         struct in_addr group_addr;
     190           0 :         char group_str[INET_ADDRSTRLEN];
     191           0 :         struct in_addr from = ip_hdr->ip_src;
     192             : 
     193           0 :         on_trace(__func__, igmp->interface, from);
     194             : 
     195           0 :         if (igmp->mtrace_only)
     196             :                 return 0;
     197             : 
     198           0 :         if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
     199           0 :                 if (PIM_DEBUG_GM_PACKETS)
     200           0 :                         zlog_debug(
     201             :                                 "Recv IGMPv2 LEAVE from %s on %s: size=%d other than correct=%d",
     202             :                                 from_str, ifp->name, igmp_msg_len,
     203             :                                 IGMP_V12_MSG_SIZE);
     204             :         }
     205             : 
     206           0 :         if (igmp_validate_checksum(igmp_msg, igmp_msg_len) == -1) {
     207           0 :                 zlog_warn(
     208             :                         "Recv IGMPv2 LEAVE from %s on %s with invalid checksum",
     209             :                         from_str, ifp->name);
     210           0 :                 return -1;
     211             :         }
     212             : 
     213             : 
     214           0 :         memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
     215             : 
     216           0 :         if (PIM_DEBUG_GM_PACKETS) {
     217           0 :                 pim_inet4_dump("<dst?>", group_addr, group_str,
     218             :                                sizeof(group_str));
     219           0 :                 zlog_debug("Recv IGMPv2 LEAVE from %s on %s for %s", from_str,
     220             :                            ifp->name, group_str);
     221             :         }
     222             :         /*
     223             :          * As per RFC 2236, section 9:
     224             :          Message Type                  Destination Group
     225             :          ------------                  -----------------
     226             :          General Query                 ALL-SYSTEMS (224.0.0.1)
     227             :          Group-Specific Query          The group being queried
     228             :          Membership Report             The group being reported
     229             :          Leave Message                 ALL-ROUTERS (224.0.0.2)
     230             : 
     231             :          Note: in older (i.e., non-standard and now obsolete) versions of
     232             :          IGMPv2, hosts send Leave Messages to the group being left.  A
     233             :          router SHOULD accept Leave Messages addressed to the group being
     234             :          left in the interests of backwards compatibility with such hosts.
     235             :          In all cases, however, hosts MUST send to the ALL-ROUTERS address
     236             :          to be compliant with this specification.
     237             :         */
     238           0 :         if ((ntohl(ip_hdr->ip_dst.s_addr) != INADDR_ALLRTRS_GROUP)
     239           0 :             && (ip_hdr->ip_dst.s_addr != group_addr.s_addr)) {
     240           0 :                 if (PIM_DEBUG_GM_EVENTS)
     241           0 :                         zlog_debug(
     242             :                                 "IGMPv2 Leave message is ignored since received on address other than ALL-ROUTERS or Group-address");
     243           0 :                 return -1;
     244             :         }
     245             : 
     246             :         /* Collecting IGMP Rx stats */
     247           0 :         igmp->igmp_stats.leave_v2++;
     248             : 
     249             :         /*
     250             :          * RFC 3376
     251             :          * 7.3.2. In the Presence of Older Version Group Members
     252             :          *
     253             :          * When Group Compatibility Mode is IGMPv2, a router internally
     254             :          * translates the following IGMPv2 messages for that group to their
     255             :          * IGMPv3 equivalents:
     256             :          *
     257             :          * IGMPv2 Message                IGMPv3 Equivalent
     258             :          * --------------                -----------------
     259             :          * Report                        IS_EX( {} )
     260             :          * Leave                         TO_IN( {} )
     261             :          */
     262           0 :         igmpv3_report_toin(igmp, from, group_addr, 0, NULL);
     263             : 
     264           0 :         return 0;
     265             : }

Generated by: LCOV version v1.16-topotato