back to topotato report
topotato coverage report
Current view: top level - pimd - pim_igmp_mtrace.c (source / functions) Hit Total Coverage
Test: test_pim_bfd.py::PIMBFDTest Lines: 0 441 0.0 %
Date: 2023-02-24 18:39:40 Functions: 0 14 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Multicast traceroute for FRRouting
       3             :  * Copyright (C) 2017  Mladen Sablic
       4             :  *
       5             :  * This program is free software; you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation; either version 2 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful, but
      11             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License along
      16             :  * with this program; see the file COPYING; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      18             :  */
      19             : 
      20             : /* based on draft-ietf-idmr-traceroute-ipm-07 */
      21             : 
      22             : #include <zebra.h>
      23             : 
      24             : #include "pimd.h"
      25             : #include "pim_instance.h"
      26             : #include "pim_util.h"
      27             : #include "pim_sock.h"
      28             : #include "pim_rp.h"
      29             : #include "pim_oil.h"
      30             : #include "pim_ifchannel.h"
      31             : #include "pim_macro.h"
      32             : #include "pim_igmp_mtrace.h"
      33             : 
      34           0 : static struct in_addr mtrace_primary_address(struct interface *ifp)
      35             : {
      36           0 :         struct connected *ifc;
      37           0 :         struct listnode *node;
      38           0 :         struct in_addr any;
      39           0 :         struct pim_interface *pim_ifp;
      40             : 
      41           0 :         if (ifp->info) {
      42           0 :                 pim_ifp = ifp->info;
      43           0 :                 return pim_ifp->primary_address;
      44             :         }
      45             : 
      46           0 :         any.s_addr = INADDR_ANY;
      47             : 
      48           0 :         for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
      49           0 :                 struct prefix *p = ifc->address;
      50             : 
      51           0 :                 if (p->family != AF_INET)
      52           0 :                         continue;
      53             : 
      54           0 :                 if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
      55           0 :                         return p->u.prefix4;
      56             :                 /* in case no primary found, return a secondary */
      57           0 :                 any = p->u.prefix4;
      58             :         }
      59           0 :         return any;
      60             : }
      61             : 
      62           0 : static bool mtrace_fwd_info_weak(struct pim_instance *pim,
      63             :                                     struct igmp_mtrace *mtracep,
      64             :                                     struct igmp_mtrace_rsp *rspp,
      65             :                                     struct interface **ifpp)
      66             : {
      67           0 :         struct pim_nexthop nexthop;
      68           0 :         struct interface *ifp_in;
      69           0 :         struct in_addr nh_addr;
      70             : 
      71           0 :         nh_addr.s_addr = INADDR_ANY;
      72             : 
      73           0 :         memset(&nexthop, 0, sizeof(nexthop));
      74             : 
      75           0 :         if (!pim_nexthop_lookup(pim, &nexthop, mtracep->src_addr, 1)) {
      76           0 :                 if (PIM_DEBUG_MTRACE)
      77           0 :                         zlog_debug("mtrace not found neighbor");
      78           0 :                 return false;
      79             :         }
      80             : 
      81           0 :         if (PIM_DEBUG_MTRACE)
      82           0 :                 zlog_debug("mtrace pim_nexthop_lookup OK");
      83             : 
      84           0 :         if (PIM_DEBUG_MTRACE)
      85           0 :                 zlog_debug("mtrace next_hop=%pPAs", &nexthop.mrib_nexthop_addr);
      86             : 
      87           0 :         nh_addr = nexthop.mrib_nexthop_addr;
      88             : 
      89           0 :         ifp_in = nexthop.interface;
      90             : 
      91             :         /* return interface for forwarding mtrace packets */
      92           0 :         *ifpp = ifp_in;
      93             : 
      94             :         /* 6.2.2. 4. Fill in the Incoming Interface Address... */
      95           0 :         rspp->incoming = mtrace_primary_address(ifp_in);
      96           0 :         rspp->prev_hop = nh_addr;
      97           0 :         rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
      98           0 :         rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
      99           0 :         rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
     100           0 :         return true;
     101             : }
     102             : 
     103           0 : static bool mtrace_fwd_info(struct pim_instance *pim,
     104             :                             struct igmp_mtrace *mtracep,
     105             :                             struct igmp_mtrace_rsp *rspp,
     106             :                             struct interface **ifpp)
     107             : {
     108           0 :         pim_sgaddr sg;
     109           0 :         struct pim_upstream *up;
     110           0 :         struct interface *ifp_in;
     111           0 :         struct in_addr nh_addr;
     112           0 :         uint32_t total;
     113             : 
     114           0 :         memset(&sg, 0, sizeof(sg));
     115           0 :         sg.src = mtracep->src_addr;
     116           0 :         sg.grp = mtracep->grp_addr;
     117             : 
     118           0 :         up = pim_upstream_find(pim, &sg);
     119             : 
     120           0 :         if (!up) {
     121           0 :                 sg.src = PIMADDR_ANY;
     122           0 :                 up = pim_upstream_find(pim, &sg);
     123             :         }
     124             : 
     125           0 :         if (!up)
     126             :                 return false;
     127             : 
     128           0 :         if (!up->rpf.source_nexthop.interface) {
     129           0 :                 if (PIM_DEBUG_TRACE)
     130           0 :                         zlog_debug("%s: up %s RPF is not present", __func__,
     131             :                                    up->sg_str);
     132           0 :                 return false;
     133             :         }
     134             : 
     135           0 :         ifp_in = up->rpf.source_nexthop.interface;
     136           0 :         nh_addr = up->rpf.source_nexthop.mrib_nexthop_addr;
     137           0 :         total = htonl(MTRACE_UNKNOWN_COUNT);
     138             : 
     139           0 :         if (PIM_DEBUG_MTRACE)
     140           0 :                 zlog_debug("fwd_info: upstream next hop=%pI4", &nh_addr);
     141             : 
     142           0 :         if (up->channel_oil)
     143           0 :                 total = up->channel_oil->cc.pktcnt;
     144             : 
     145             :         /* return interface for forwarding mtrace packets */
     146           0 :         *ifpp = ifp_in;
     147             : 
     148             :         /* 6.2.2. 4. Fill in the Incoming Interface Address... */
     149           0 :         rspp->incoming = mtrace_primary_address(ifp_in);
     150           0 :         rspp->prev_hop = nh_addr;
     151           0 :         rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
     152           0 :         rspp->total = total;
     153           0 :         rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
     154             : 
     155             :         /* 6.2.2. 4. Fill in ... S, and Src Mask */
     156           0 :         if (!pim_addr_is_any(sg.src)) {
     157           0 :                 rspp->s = 1;
     158           0 :                 rspp->src_mask = MTRACE_SRC_MASK_SOURCE;
     159             :         } else {
     160           0 :                 rspp->s = 0;
     161           0 :                 rspp->src_mask = MTRACE_SRC_MASK_GROUP;
     162             :         }
     163             : 
     164             :         return true;
     165             : }
     166             : 
     167           0 : static void mtrace_rsp_set_fwd_code(struct igmp_mtrace_rsp *mtrace_rspp,
     168             :                                     enum mtrace_fwd_code fwd_code)
     169             : {
     170           0 :         if (mtrace_rspp->fwd_code == MTRACE_FWD_CODE_NO_ERROR)
     171           0 :                 mtrace_rspp->fwd_code = fwd_code;
     172             : }
     173             : 
     174           0 : static void mtrace_rsp_init(struct igmp_mtrace_rsp *mtrace_rspp)
     175             : {
     176           0 :         mtrace_rspp->arrival = 0;
     177           0 :         mtrace_rspp->incoming.s_addr = INADDR_ANY;
     178           0 :         mtrace_rspp->outgoing.s_addr = INADDR_ANY;
     179           0 :         mtrace_rspp->prev_hop.s_addr = INADDR_ANY;
     180           0 :         mtrace_rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
     181           0 :         mtrace_rspp->out_count = htonl(MTRACE_UNKNOWN_COUNT);
     182           0 :         mtrace_rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
     183           0 :         mtrace_rspp->rtg_proto = 0;
     184           0 :         mtrace_rspp->fwd_ttl = 0;
     185           0 :         mtrace_rspp->mbz = 0;
     186           0 :         mtrace_rspp->s = 0;
     187           0 :         mtrace_rspp->src_mask = 0;
     188           0 :         mtrace_rspp->fwd_code = MTRACE_FWD_CODE_NO_ERROR;
     189             : }
     190             : 
     191           0 : static void mtrace_rsp_debug(uint32_t qry_id, int rsp,
     192             :                              struct igmp_mtrace_rsp *mrspp)
     193             : {
     194           0 :         struct in_addr incoming = mrspp->incoming;
     195           0 :         struct in_addr outgoing = mrspp->outgoing;
     196           0 :         struct in_addr prev_hop = mrspp->prev_hop;
     197             : 
     198           0 :         zlog_debug(
     199             :                 "Rx mt(%d) qid=%ud arr=%x in=%pI4 out=%pI4 prev=%pI4 proto=%d fwd=%d",
     200             :                 rsp, ntohl(qry_id), mrspp->arrival, &incoming, &outgoing,
     201             :                 &prev_hop, mrspp->rtg_proto, mrspp->fwd_code);
     202           0 : }
     203             : 
     204           0 : static void mtrace_debug(struct pim_interface *pim_ifp,
     205             :                          struct igmp_mtrace *mtracep, int mtrace_len)
     206             : {
     207           0 :         struct in_addr ga, sa, da, ra;
     208             : 
     209           0 :         ga = mtracep->grp_addr;
     210           0 :         sa = mtracep->src_addr;
     211           0 :         da = mtracep->dst_addr;
     212           0 :         ra = mtracep->rsp_addr;
     213             : 
     214           0 :         zlog_debug(
     215             :                 "Rx mtrace packet incoming on %pI4: hops=%d type=%d size=%d, grp=%pI4, src=%pI4, dst=%pI4 rsp=%pI4 ttl=%d qid=%ud",
     216             :                 &pim_ifp->primary_address, mtracep->hops, mtracep->type,
     217             :                 mtrace_len, &ga, &sa, &da, &ra, mtracep->rsp_ttl,
     218             :                 ntohl(mtracep->qry_id));
     219           0 :         if (mtrace_len > (int)sizeof(struct igmp_mtrace)) {
     220             : 
     221           0 :                 int i;
     222             : 
     223           0 :                 int responses = mtrace_len - sizeof(struct igmp_mtrace);
     224             : 
     225           0 :                 if ((responses % sizeof(struct igmp_mtrace_rsp)) != 0)
     226           0 :                         if (PIM_DEBUG_MTRACE)
     227           0 :                                 zlog_debug(
     228             :                                         "Mtrace response block of wrong length");
     229             : 
     230           0 :                 responses = responses / sizeof(struct igmp_mtrace_rsp);
     231             : 
     232           0 :                 for (i = 0; i < responses; i++)
     233           0 :                         mtrace_rsp_debug(mtracep->qry_id, i, &mtracep->rsp[i]);
     234             :         }
     235           0 : }
     236             : 
     237             : /* 5.1 Query Arrival Time */
     238           0 : static uint32_t query_arrival_time(void)
     239             : {
     240           0 :         struct timeval tv;
     241           0 :         uint32_t qat;
     242             : 
     243           0 :         if (gettimeofday(&tv, NULL) < 0) {
     244           0 :                 if (PIM_DEBUG_MTRACE)
     245           0 :                         zlog_debug("Query arrival time lookup failed: errno=%d: %s",
     246             :                                    errno, safe_strerror(errno));
     247           0 :                 return 0;
     248             :         }
     249             :         /* not sure second offset correct, as I get different value */
     250           0 :         qat = ((tv.tv_sec + 32384) << 16) + ((tv.tv_usec << 10) / 15625);
     251             : 
     252           0 :         return qat;
     253             : }
     254             : 
     255           0 : static int mtrace_send_packet(struct interface *ifp,
     256             :                               struct igmp_mtrace *mtracep,
     257             :                               size_t mtrace_buf_len, struct in_addr dst_addr,
     258             :                               struct in_addr group_addr)
     259             : {
     260           0 :         struct sockaddr_in to;
     261           0 :         socklen_t tolen;
     262           0 :         ssize_t sent;
     263           0 :         int ret;
     264           0 :         int fd;
     265           0 :         uint8_t ttl;
     266             : 
     267           0 :         memset(&to, 0, sizeof(to));
     268           0 :         to.sin_family = AF_INET;
     269           0 :         to.sin_addr = dst_addr;
     270           0 :         tolen = sizeof(to);
     271             : 
     272           0 :         if (PIM_DEBUG_MTRACE) {
     273           0 :                 struct in_addr if_addr;
     274           0 :                 struct in_addr rsp_addr = mtracep->rsp_addr;
     275             : 
     276           0 :                 if_addr = mtrace_primary_address(ifp);
     277           0 :                 zlog_debug("Sending mtrace packet to %pI4 on %pI4", &rsp_addr,
     278             :                            &if_addr);
     279             :         }
     280             : 
     281           0 :         fd = pim_socket_raw(IPPROTO_IGMP);
     282             : 
     283           0 :         if (fd < 0)
     284             :                 return -1;
     285             : 
     286           0 :         ret = pim_socket_bind(fd, ifp);
     287             : 
     288           0 :         if (ret < 0) {
     289           0 :                 ret = -1;
     290           0 :                 goto close_fd;
     291             :         }
     292             : 
     293           0 :         if (IPV4_CLASS_DE(ntohl(dst_addr.s_addr))) {
     294           0 :                 if (IPV4_MC_LINKLOCAL(ntohl(dst_addr.s_addr))) {
     295           0 :                         ttl = 1;
     296             :                 } else {
     297           0 :                         if (mtracep->type == PIM_IGMP_MTRACE_RESPONSE)
     298           0 :                                 ttl = mtracep->rsp_ttl;
     299             :                         else
     300           0 :                                 ttl = 64;
     301             :                 }
     302           0 :                 ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
     303             :                                  sizeof(ttl));
     304             : 
     305           0 :                 if (ret < 0) {
     306           0 :                         if (PIM_DEBUG_MTRACE)
     307           0 :                                 zlog_debug("Failed to set socket multicast TTL");
     308           0 :                         ret = -1;
     309           0 :                         goto close_fd;
     310             :                 }
     311             :         }
     312             : 
     313           0 :         sent = sendto(fd, (char *)mtracep, mtrace_buf_len, MSG_DONTWAIT,
     314             :                       (struct sockaddr *)&to, tolen);
     315             : 
     316           0 :         if (sent != (ssize_t)mtrace_buf_len) {
     317           0 :                 char dst_str[INET_ADDRSTRLEN];
     318           0 :                 char group_str[INET_ADDRSTRLEN];
     319             : 
     320           0 :                 pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
     321           0 :                 pim_inet4_dump("<group?>", group_addr, group_str,
     322             :                                sizeof(group_str));
     323           0 :                 if (sent < 0) {
     324           0 :                         if (PIM_DEBUG_MTRACE)
     325           0 :                                 zlog_debug(
     326             :                                         "Send mtrace request failed for %s on%s: group=%s msg_size=%zd: errno=%d:  %s",
     327             :                                         dst_str, ifp->name, group_str,
     328             :                                         mtrace_buf_len, errno,
     329             :                                         safe_strerror(errno));
     330             :                 } else {
     331           0 :                         if (PIM_DEBUG_MTRACE)
     332           0 :                                 zlog_debug(
     333             :                                         "Send mtrace request failed for %s on %s: group=%s msg_size=%zd: sent=%zd",
     334             :                                         dst_str, ifp->name, group_str,
     335             :                                         mtrace_buf_len, sent);
     336             :                 }
     337           0 :                 ret = -1;
     338           0 :                 goto close_fd;
     339             :         }
     340             :         ret = 0;
     341           0 : close_fd:
     342           0 :         close(fd);
     343           0 :         return ret;
     344             : }
     345             : 
     346           0 : static int mtrace_un_forward_packet(struct pim_instance *pim, struct ip *ip_hdr,
     347             :                                     struct interface *interface)
     348             : {
     349           0 :         struct pim_nexthop nexthop;
     350           0 :         struct sockaddr_in to;
     351           0 :         struct interface *if_out;
     352           0 :         socklen_t tolen;
     353           0 :         int ret;
     354           0 :         int fd;
     355           0 :         int sent;
     356           0 :         uint16_t checksum;
     357             : 
     358           0 :         checksum = ip_hdr->ip_sum;
     359             : 
     360           0 :         ip_hdr->ip_sum = 0;
     361             : 
     362           0 :         if (checksum != in_cksum(ip_hdr, ip_hdr->ip_hl * 4))
     363             :                 return -1;
     364             : 
     365           0 :         if (ip_hdr->ip_ttl-- <= 1)
     366             :                 return -1;
     367             : 
     368           0 :         if (interface == NULL) {
     369           0 :                 memset(&nexthop, 0, sizeof(nexthop));
     370           0 :                 if (!pim_nexthop_lookup(pim, &nexthop, ip_hdr->ip_dst, 0)) {
     371           0 :                         if (PIM_DEBUG_MTRACE)
     372           0 :                                 zlog_debug(
     373             :                                         "Dropping mtrace packet, no route to destination");
     374           0 :                         return -1;
     375             :                 }
     376             : 
     377           0 :                 if_out = nexthop.interface;
     378             :         } else {
     379             :                 if_out = interface;
     380             :         }
     381             : 
     382           0 :         ip_hdr->ip_sum = in_cksum(ip_hdr, ip_hdr->ip_hl * 4);
     383             : 
     384           0 :         fd = pim_socket_raw(IPPROTO_RAW);
     385             : 
     386           0 :         if (fd < 0)
     387             :                 return -1;
     388             : 
     389           0 :         pim_socket_ip_hdr(fd);
     390             : 
     391           0 :         ret = pim_socket_bind(fd, if_out);
     392             : 
     393           0 :         if (ret < 0) {
     394           0 :                 close(fd);
     395           0 :                 return -1;
     396             :         }
     397             : 
     398           0 :         memset(&to, 0, sizeof(to));
     399           0 :         to.sin_family = AF_INET;
     400           0 :         to.sin_addr = ip_hdr->ip_dst;
     401           0 :         tolen = sizeof(to);
     402             : 
     403           0 :         sent = sendto(fd, ip_hdr, ntohs(ip_hdr->ip_len), 0,
     404             :                       (struct sockaddr *)&to, tolen);
     405             : 
     406           0 :         close(fd);
     407             : 
     408           0 :         if (sent < 0) {
     409           0 :                 if (PIM_DEBUG_MTRACE)
     410           0 :                         zlog_debug(
     411             :                                 "Failed to forward mtrace packet: sendto errno=%d, %s",
     412             :                                 errno, safe_strerror(errno));
     413           0 :                 return -1;
     414             :         }
     415             : 
     416           0 :         if (PIM_DEBUG_MTRACE) {
     417           0 :                 zlog_debug("Fwd mtrace packet len=%u to %pI4 ttl=%u",
     418             :                            ntohs(ip_hdr->ip_len), &ip_hdr->ip_dst,
     419             :                            ip_hdr->ip_ttl);
     420             :         }
     421             : 
     422             :         return 0;
     423             : }
     424             : 
     425           0 : static int mtrace_mc_forward_packet(struct pim_instance *pim, struct ip *ip_hdr)
     426             : {
     427           0 :         pim_sgaddr sg;
     428           0 :         struct channel_oil *c_oil;
     429           0 :         struct listnode *chnode;
     430           0 :         struct listnode *chnextnode;
     431           0 :         struct pim_ifchannel *ch = NULL;
     432           0 :         int ret = -1;
     433             : 
     434           0 :         memset(&sg, 0, sizeof(sg));
     435           0 :         sg.grp = ip_hdr->ip_dst;
     436             : 
     437           0 :         c_oil = pim_find_channel_oil(pim, &sg);
     438             : 
     439           0 :         if (c_oil == NULL) {
     440           0 :                 if (PIM_DEBUG_MTRACE) {
     441           0 :                         zlog_debug(
     442             :                                 "Dropping mtrace multicast packet len=%u to %pI4 ttl=%u",
     443             :                                 ntohs(ip_hdr->ip_len),
     444             :                                 &ip_hdr->ip_dst, ip_hdr->ip_ttl);
     445             :                 }
     446           0 :                 return -1;
     447             :         }
     448           0 :         if (c_oil->up == NULL)
     449             :                 return -1;
     450           0 :         if (c_oil->up->ifchannels == NULL)
     451             :                 return -1;
     452           0 :         for (ALL_LIST_ELEMENTS(c_oil->up->ifchannels, chnode, chnextnode, ch)) {
     453           0 :                 if (pim_macro_chisin_oiflist(ch)) {
     454           0 :                         int r;
     455             : 
     456           0 :                         r = mtrace_un_forward_packet(pim, ip_hdr,
     457             :                                                      ch->interface);
     458           0 :                         if (r == 0)
     459           0 :                                 ret = 0;
     460             :                 }
     461             :         }
     462             :         return ret;
     463             : }
     464             : 
     465             : 
     466           0 : static int mtrace_forward_packet(struct pim_instance *pim, struct ip *ip_hdr)
     467             : {
     468           0 :         if (IPV4_CLASS_DE(ntohl(ip_hdr->ip_dst.s_addr)))
     469           0 :                 return mtrace_mc_forward_packet(pim, ip_hdr);
     470             :         else
     471           0 :                 return mtrace_un_forward_packet(pim, ip_hdr, NULL);
     472             : }
     473             : 
     474           0 : static int mtrace_send_mc_response(struct pim_instance *pim,
     475             :                                    struct igmp_mtrace *mtracep,
     476             :                                    size_t mtrace_len)
     477             : {
     478           0 :         pim_sgaddr sg;
     479           0 :         struct channel_oil *c_oil;
     480           0 :         struct listnode *chnode;
     481           0 :         struct listnode *chnextnode;
     482           0 :         struct pim_ifchannel *ch = NULL;
     483           0 :         int ret = -1;
     484             : 
     485           0 :         memset(&sg, 0, sizeof(sg));
     486           0 :         sg.grp = mtracep->rsp_addr;
     487             : 
     488           0 :         c_oil = pim_find_channel_oil(pim, &sg);
     489             : 
     490           0 :         if (c_oil == NULL) {
     491           0 :                 if (PIM_DEBUG_MTRACE) {
     492           0 :                         struct in_addr rsp_addr = mtracep->rsp_addr;
     493             : 
     494           0 :                         zlog_debug(
     495             :                                 "Dropping mtrace multicast response packet len=%u to %pI4",
     496             :                                 (unsigned int)mtrace_len, &rsp_addr);
     497             :                 }
     498           0 :                 return -1;
     499             :         }
     500           0 :         if (c_oil->up == NULL)
     501             :                 return -1;
     502           0 :         if (c_oil->up->ifchannels == NULL)
     503             :                 return -1;
     504           0 :         for (ALL_LIST_ELEMENTS(c_oil->up->ifchannels, chnode, chnextnode, ch)) {
     505           0 :                 if (pim_macro_chisin_oiflist(ch)) {
     506           0 :                         int r;
     507             : 
     508           0 :                         r = mtrace_send_packet(ch->interface, mtracep,
     509             :                                                mtrace_len, mtracep->rsp_addr,
     510             :                                                mtracep->grp_addr);
     511           0 :                         if (r == 0)
     512           0 :                                 ret = 0;
     513             :                 }
     514             :         }
     515             :         return ret;
     516             : }
     517             : 
     518             : /* 6.5 Sending Traceroute Responses */
     519           0 : static int mtrace_send_response(struct pim_instance *pim,
     520             :                                 struct igmp_mtrace *mtracep, size_t mtrace_len)
     521             : {
     522           0 :         struct pim_nexthop nexthop;
     523             : 
     524           0 :         mtracep->type = PIM_IGMP_MTRACE_RESPONSE;
     525             : 
     526           0 :         mtracep->checksum = 0;
     527           0 :         mtracep->checksum = in_cksum((char *)mtracep, mtrace_len);
     528             : 
     529           0 :         if (IPV4_CLASS_DE(ntohl(mtracep->rsp_addr.s_addr))) {
     530           0 :                 struct pim_rpf *p_rpf;
     531             : 
     532           0 :                 if (pim_rp_i_am_rp(pim, mtracep->rsp_addr))
     533           0 :                         return mtrace_send_mc_response(pim, mtracep,
     534             :                                                        mtrace_len);
     535             : 
     536           0 :                 p_rpf = pim_rp_g(pim, mtracep->rsp_addr);
     537             : 
     538           0 :                 if (p_rpf == NULL) {
     539           0 :                         if (PIM_DEBUG_MTRACE) {
     540           0 :                                 struct in_addr rsp_addr = mtracep->rsp_addr;
     541             : 
     542           0 :                                 zlog_debug("mtrace no RP for %pI4", &rsp_addr);
     543             :                         }
     544           0 :                         return -1;
     545             :                 }
     546           0 :                 nexthop = p_rpf->source_nexthop;
     547           0 :                 if (PIM_DEBUG_MTRACE)
     548           0 :                         zlog_debug("mtrace response to RP");
     549             :         } else {
     550           0 :                 memset(&nexthop, 0, sizeof(nexthop));
     551             :                 /* TODO: should use unicast rib lookup */
     552           0 :                 if (!pim_nexthop_lookup(pim, &nexthop, mtracep->rsp_addr, 1)) {
     553           0 :                         if (PIM_DEBUG_MTRACE)
     554           0 :                                 zlog_debug(
     555             :                                         "Dropped response qid=%ud, no route to response address",
     556             :                                         mtracep->qry_id);
     557           0 :                         return -1;
     558             :                 }
     559             :         }
     560             : 
     561           0 :         return mtrace_send_packet(nexthop.interface, mtracep, mtrace_len,
     562             :                                   mtracep->rsp_addr, mtracep->grp_addr);
     563             : }
     564             : 
     565           0 : int igmp_mtrace_recv_qry_req(struct gm_sock *igmp, struct ip *ip_hdr,
     566             :                              struct in_addr from, const char *from_str,
     567             :                              char *igmp_msg, int igmp_msg_len)
     568             : {
     569           0 :         static uint32_t qry_id, qry_src;
     570           0 :         char mtrace_buf[MTRACE_HDR_SIZE + MTRACE_MAX_HOPS * MTRACE_RSP_SIZE];
     571           0 :         struct interface *ifp;
     572           0 :         struct interface *out_ifp = NULL;
     573           0 :         struct pim_interface *pim_ifp;
     574           0 :         struct pim_instance *pim;
     575           0 :         struct igmp_mtrace *mtracep;
     576           0 :         struct igmp_mtrace_rsp *rspp;
     577           0 :         struct in_addr nh_addr;
     578           0 :         enum mtrace_fwd_code fwd_code = MTRACE_FWD_CODE_NO_ERROR;
     579           0 :         size_t r_len;
     580           0 :         int last_rsp_ind = 0;
     581           0 :         size_t mtrace_len;
     582           0 :         uint16_t recv_checksum;
     583           0 :         uint16_t checksum;
     584           0 :         bool reached_source;
     585           0 :         bool fwd_info;
     586             : 
     587           0 :         ifp = igmp->interface;
     588           0 :         pim_ifp = ifp->info;
     589           0 :         pim = pim_ifp->pim;
     590             : 
     591             :         /*
     592             :          * 6. Router Behaviour
     593             :          * Check if mtrace packet is addressed elsewhere and forward,
     594             :          * if applicable
     595             :          */
     596           0 :         if (!IPV4_CLASS_DE(ntohl(ip_hdr->ip_dst.s_addr)))
     597           0 :                 if (!if_address_is_local(&ip_hdr->ip_dst, AF_INET,
     598           0 :                                          pim->vrf->vrf_id))
     599           0 :                         return mtrace_forward_packet(pim, ip_hdr);
     600             : 
     601           0 :         if (igmp_msg_len < (int)sizeof(struct igmp_mtrace)) {
     602           0 :                 if (PIM_DEBUG_MTRACE)
     603           0 :                         zlog_debug(
     604             :                                 "Recv mtrace packet from %s on %s: too short, len=%d, min=%zu",
     605             :                                 from_str, ifp->name, igmp_msg_len,
     606             :                                 sizeof(struct igmp_mtrace));
     607           0 :                 return -1;
     608             :         }
     609             : 
     610           0 :         mtracep = (struct igmp_mtrace *)igmp_msg;
     611             : 
     612           0 :         recv_checksum = mtracep->checksum;
     613             : 
     614           0 :         mtracep->checksum = 0;
     615             : 
     616           0 :         checksum = in_cksum(igmp_msg, igmp_msg_len);
     617             : 
     618           0 :         if (recv_checksum != checksum) {
     619           0 :                 if (PIM_DEBUG_MTRACE)
     620           0 :                         zlog_debug(
     621             :                                 "Recv mtrace packet from %s on %s: checksum mismatch: received=%x computed=%x",
     622             :                                 from_str, ifp->name, recv_checksum, checksum);
     623           0 :                 return -1;
     624             :         }
     625             : 
     626             :         /* Collecting IGMP Rx stats */
     627           0 :         igmp->igmp_stats.mtrace_req++;
     628             : 
     629           0 :         if (PIM_DEBUG_MTRACE)
     630           0 :                 mtrace_debug(pim_ifp, mtracep, igmp_msg_len);
     631             : 
     632             :         /* subtract header from message length */
     633           0 :         r_len = igmp_msg_len - sizeof(struct igmp_mtrace);
     634             : 
     635             :         /* Classify mtrace packet, check if it is a query */
     636           0 :         if (!r_len) {
     637           0 :                 if (PIM_DEBUG_MTRACE)
     638           0 :                         zlog_debug("Received IGMP multicast traceroute query");
     639             : 
     640             :                 /* 6.1.1  Packet verification */
     641           0 :                 if (!pim_if_connected_to_source(ifp, mtracep->dst_addr)) {
     642           0 :                         if (IPV4_CLASS_DE(ntohl(ip_hdr->ip_dst.s_addr))) {
     643           0 :                                 if (PIM_DEBUG_MTRACE)
     644           0 :                                         zlog_debug(
     645             :                                                 "Dropping multicast query on wrong interface");
     646           0 :                                 return -1;
     647             :                         }
     648             :                         /* Unicast query on wrong interface */
     649           0 :                         fwd_code = MTRACE_FWD_CODE_WRONG_IF;
     650           0 :                         if (PIM_DEBUG_MTRACE)
     651           0 :                                 zlog_debug("Multicast query on wrong interface");
     652             :                 }
     653           0 :                 if (qry_id == mtracep->qry_id && qry_src == from.s_addr) {
     654           0 :                         if (PIM_DEBUG_MTRACE)
     655           0 :                                 zlog_debug(
     656             :                                         "Dropping multicast query with duplicate source and id");
     657           0 :                         return -1;
     658             :                 }
     659           0 :                 qry_id = mtracep->qry_id;
     660           0 :                 qry_src = from.s_addr;
     661             :         }
     662             :         /* if response fields length is equal to a whole number of responses */
     663           0 :         else if ((r_len % sizeof(struct igmp_mtrace_rsp)) == 0) {
     664           0 :                 r_len = igmp_msg_len - sizeof(struct igmp_mtrace);
     665             : 
     666           0 :                 if (r_len != 0)
     667           0 :                         last_rsp_ind = r_len / sizeof(struct igmp_mtrace_rsp);
     668           0 :                 if (last_rsp_ind > MTRACE_MAX_HOPS) {
     669           0 :                         if (PIM_DEBUG_MTRACE)
     670           0 :                                 zlog_debug("Mtrace request of excessive size");
     671           0 :                         return -1;
     672             :                 }
     673             :         } else {
     674           0 :                 if (PIM_DEBUG_MTRACE)
     675           0 :                         zlog_debug(
     676             :                                 "Recv mtrace packet from %s on %s: invalid length %d",
     677             :                                 from_str, ifp->name, igmp_msg_len);
     678           0 :                 return -1;
     679             :         }
     680             : 
     681             :         /* 6.2.1 Packet Verification - drop not link-local multicast */
     682           0 :         if (IPV4_CLASS_DE(ntohl(ip_hdr->ip_dst.s_addr))
     683           0 :             && !IPV4_MC_LINKLOCAL(ntohl(ip_hdr->ip_dst.s_addr))) {
     684           0 :                 if (PIM_DEBUG_MTRACE)
     685           0 :                         zlog_debug(
     686             :                                 "Recv mtrace packet from %s on %s: not link-local multicast %pI4",
     687             :                                 from_str, ifp->name, &ip_hdr->ip_dst);
     688           0 :                 return -1;
     689             :         }
     690             : 
     691             :         /* 6.2.2. Normal Processing */
     692             : 
     693             :         /* 6.2.2. 1. If there is room in the current buffer? */
     694             : 
     695           0 :         if (last_rsp_ind == MTRACE_MAX_HOPS) {
     696             :                 /* ...there was no room... */
     697           0 :                 mtracep->rsp[MTRACE_MAX_HOPS - 1].fwd_code =
     698             :                         MTRACE_FWD_CODE_NO_SPACE;
     699           0 :                 return mtrace_send_response(pim_ifp->pim, mtracep,
     700             :                                             igmp_msg_len);
     701             :         }
     702             : 
     703             :         /* ...insert new response block... */
     704             : 
     705             :         /* calculate new mtrace lenght with extra response */
     706           0 :         mtrace_len = igmp_msg_len + sizeof(struct igmp_mtrace_rsp);
     707             : 
     708             :         /* copy received query/request */
     709           0 :         memcpy(mtrace_buf, igmp_msg, igmp_msg_len);
     710             : 
     711             :         /* repoint mtracep pointer to copy */
     712           0 :         mtracep = (struct igmp_mtrace *)mtrace_buf;
     713             : 
     714             :         /* pointer for extra response field to be filled in */
     715           0 :         rspp = &mtracep->rsp[last_rsp_ind];
     716             : 
     717             :         /* initialize extra response field */
     718           0 :         mtrace_rsp_init(rspp);
     719             : 
     720             :         /* carry over any error noted when receiving the query */
     721           0 :         rspp->fwd_code = fwd_code;
     722             : 
     723             :         /* ...and fill in Query Arrival Time... */
     724           0 :         rspp->arrival = htonl(query_arrival_time());
     725           0 :         rspp->outgoing = pim_ifp->primary_address;
     726           0 :         rspp->out_count = htonl(MTRACE_UNKNOWN_COUNT);
     727           0 :         rspp->fwd_ttl = 1;
     728             : 
     729             :         /* 6.2.2. 2. Attempt to determine the forwarding information... */
     730             : 
     731           0 :         if (mtracep->grp_addr.s_addr != INADDR_ANY)
     732           0 :                 fwd_info = mtrace_fwd_info(pim, mtracep, rspp, &out_ifp);
     733             :         else
     734           0 :                 fwd_info = mtrace_fwd_info_weak(pim, mtracep, rspp, &out_ifp);
     735             : 
     736             :         /* 6.2.2 3. If no forwarding information... */
     737           0 :         if (!fwd_info) {
     738           0 :                 if (PIM_DEBUG_MTRACE)
     739           0 :                         zlog_debug("mtrace not found multicast state");
     740           0 :                 mtrace_rsp_set_fwd_code(rspp, MTRACE_FWD_CODE_NO_ROUTE);
     741             :                 /* 6.2.2. 3. forward the packet to requester */
     742           0 :                 return mtrace_send_response(pim, mtracep, mtrace_len);
     743             :         }
     744             : 
     745           0 :         nh_addr = rspp->prev_hop;
     746             : 
     747           0 :         reached_source = false;
     748             : 
     749           0 :         if (nh_addr.s_addr == INADDR_ANY) {
     750             :                 /* no pim? i.e. 7.5.3. No Previous Hop */
     751           0 :                 if (!out_ifp->info) {
     752           0 :                         if (PIM_DEBUG_MTRACE)
     753           0 :                                 zlog_debug("mtrace not found incoming if w/ pim");
     754           0 :                         mtrace_rsp_set_fwd_code(rspp,
     755             :                                                 MTRACE_FWD_CODE_NO_MULTICAST);
     756           0 :                         return mtrace_send_response(pim, mtracep, mtrace_len);
     757             :                 }
     758             :                 /* reached source? i.e. 7.5.1 Arriving at source */
     759           0 :                 if (pim_if_connected_to_source(out_ifp, mtracep->src_addr)) {
     760           0 :                         reached_source = true;
     761           0 :                         rspp->prev_hop = mtracep->src_addr;
     762             :                 }
     763             :                 /*
     764             :                  * 6.4 Forwarding Traceroute Requests:
     765             :                  * Previous-hop router not known,
     766             :                  * packet is sent to an appropriate multicast address
     767             :                  */
     768           0 :                 (void)inet_aton(MCAST_ALL_ROUTERS, &nh_addr);
     769             :         }
     770             : 
     771             :         /* 6.2.2 8. If this router is the Rendez-vous Point */
     772           0 :         if (mtracep->grp_addr.s_addr != INADDR_ANY &&
     773           0 :             pim_rp_i_am_rp(pim, mtracep->grp_addr)) {
     774           0 :                 mtrace_rsp_set_fwd_code(rspp, MTRACE_FWD_CODE_REACHED_RP);
     775             :                 /* 7.7.1. PIM-SM ...RP has not performed source-specific join */
     776           0 :                 if (rspp->src_mask == MTRACE_SRC_MASK_GROUP)
     777           0 :                         return mtrace_send_response(pim, mtracep, mtrace_len);
     778             :         }
     779             : 
     780             :         /*
     781             :          * 6.4 Forwarding Traceroute Requests: the number of response
     782             :          * blocks exceeds number of responses, so forward to the requester.
     783             :          */
     784           0 :         if (mtracep->hops <= (last_rsp_ind + 1))
     785           0 :                 return mtrace_send_response(pim, mtracep, mtrace_len);
     786             : 
     787             :         /* 7.5.1. Arriving at source: terminate trace */
     788           0 :         if (reached_source)
     789           0 :                 return mtrace_send_response(pim, mtracep, mtrace_len);
     790             : 
     791           0 :         mtracep->checksum = 0;
     792             : 
     793           0 :         mtracep->checksum = in_cksum(mtrace_buf, mtrace_len);
     794             : 
     795             :         /* 6.4 Forwarding Traceroute Requests: response blocks less than req. */
     796           0 :         return mtrace_send_packet(out_ifp, mtracep, mtrace_len, nh_addr,
     797             :                                   mtracep->grp_addr);
     798             : }
     799             : 
     800             : /* 6.3. Traceroute responses */
     801           0 : int igmp_mtrace_recv_response(struct gm_sock *igmp, struct ip *ip_hdr,
     802             :                               struct in_addr from, const char *from_str,
     803             :                               char *igmp_msg, int igmp_msg_len)
     804             : {
     805           0 :         static uint32_t qry_id, rsp_dst;
     806           0 :         struct interface *ifp;
     807           0 :         struct pim_interface *pim_ifp;
     808           0 :         struct pim_instance *pim;
     809           0 :         struct igmp_mtrace *mtracep;
     810           0 :         uint16_t recv_checksum;
     811           0 :         uint16_t checksum;
     812             : 
     813           0 :         ifp = igmp->interface;
     814           0 :         pim_ifp = ifp->info;
     815           0 :         pim = pim_ifp->pim;
     816             : 
     817           0 :         if (igmp_msg_len < (int)sizeof(struct igmp_mtrace)) {
     818           0 :                 if (PIM_DEBUG_MTRACE)
     819           0 :                         zlog_debug(
     820             :                                 "Recv mtrace packet from %s on %s: too short, len=%d, min=%zu",
     821             :                                 from_str, ifp->name, igmp_msg_len,
     822             :                                 sizeof(struct igmp_mtrace));
     823           0 :                 return -1;
     824             :         }
     825             : 
     826           0 :         mtracep = (struct igmp_mtrace *)igmp_msg;
     827             : 
     828           0 :         recv_checksum = mtracep->checksum;
     829             : 
     830           0 :         mtracep->checksum = 0;
     831             : 
     832           0 :         checksum = in_cksum(igmp_msg, igmp_msg_len);
     833             : 
     834           0 :         if (recv_checksum != checksum) {
     835           0 :                 if (PIM_DEBUG_MTRACE)
     836           0 :                         zlog_debug(
     837             :                                 "Recv mtrace response from %s on %s: checksum mismatch: received=%x computed=%x",
     838             :                                 from_str, ifp->name, recv_checksum, checksum);
     839           0 :                 return -1;
     840             :         }
     841             : 
     842           0 :         mtracep->checksum = checksum;
     843             : 
     844             :         /* Collecting IGMP Rx stats */
     845           0 :         igmp->igmp_stats.mtrace_rsp++;
     846             : 
     847           0 :         if (PIM_DEBUG_MTRACE)
     848           0 :                 mtrace_debug(pim_ifp, mtracep, igmp_msg_len);
     849             : 
     850             :         /* Drop duplicate packets */
     851           0 :         if (qry_id == mtracep->qry_id && rsp_dst == ip_hdr->ip_dst.s_addr) {
     852           0 :                 if (PIM_DEBUG_MTRACE)
     853           0 :                         zlog_debug("duplicate mtrace response packet dropped");
     854           0 :                 return -1;
     855             :         }
     856             : 
     857           0 :         qry_id = mtracep->qry_id;
     858           0 :         rsp_dst = ip_hdr->ip_dst.s_addr;
     859             : 
     860           0 :         return mtrace_forward_packet(pim, ip_hdr);
     861             : }

Generated by: LCOV version v1.16-topotato