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