1131087Smarcel/* 2131087Smarcel * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 3131087Smarcel * The Regents of the University of California. All rights reserved. 4131087Smarcel * 5131087Smarcel * Redistribution and use in source and binary forms, with or without 6131087Smarcel * modification, are permitted provided that: (1) source code distributions 7131087Smarcel * retain the above copyright notice and this paragraph in its entirety, (2) 8131087Smarcel * distributions including binary code include the above copyright notice and 9131087Smarcel * this paragraph in its entirety in the documentation or other materials 10131087Smarcel * provided with the distribution, and (3) all advertising materials mentioning 11131087Smarcel * features or use of this software display the following acknowledgement: 12131087Smarcel * ``This product includes software developed by the University of California, 13131087Smarcel * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14131087Smarcel * the University nor the names of its contributors may be used to endorse 15131087Smarcel * or promote products derived from this software without specific prior 16131087Smarcel * written permission. 17131087Smarcel * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18131087Smarcel * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19131087Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20131087Smarcel */ 21131087Smarcel 22131087Smarcel#ifndef lint 23131087Smarcelstatic const char rcsid[] _U_ = 24131087Smarcel "@(#) $Header: /tcpdump/master/tcpdump/print-igmp.c,v 1.15 2004-03-24 00:59:16 guy Exp $ (LBL)"; 25131087Smarcel#endif 26131087Smarcel 27131087Smarcel#ifdef HAVE_CONFIG_H 28131087Smarcel#include "config.h" 29131087Smarcel#endif 30131087Smarcel 31131087Smarcel#include <tcpdump-stdinc.h> 32131087Smarcel 33131087Smarcel#include <stdio.h> 34131087Smarcel#include <string.h> 35131087Smarcel 36131087Smarcel#include "interface.h" 37131087Smarcel#include "addrtoname.h" 38131087Smarcel#include "extract.h" /* must come after interface.h */ 39131087Smarcel 40131087Smarcel#ifndef IN_CLASSD 41131087Smarcel#define IN_CLASSD(i) (((int32_t)(i) & 0xf0000000) == 0xe0000000) 42131087Smarcel#endif 43131087Smarcel 44131087Smarcel/* (following from ipmulti/mrouted/prune.h) */ 45131087Smarcel 46131087Smarcel/* 47131087Smarcel * The packet format for a traceroute request. 48131087Smarcel */ 49131087Smarcelstruct tr_query { 50131087Smarcel u_int32_t tr_src; /* traceroute source */ 51131087Smarcel u_int32_t tr_dst; /* traceroute destination */ 52131087Smarcel u_int32_t tr_raddr; /* traceroute response address */ 53131087Smarcel u_int32_t tr_rttlqid; /* response ttl and qid */ 54131087Smarcel}; 55131087Smarcel 56131087Smarcel#define TR_GETTTL(x) (int)(((x) >> 24) & 0xff) 57131087Smarcel#define TR_GETQID(x) ((x) & 0x00ffffff) 58131087Smarcel 59131087Smarcel/* 60131087Smarcel * Traceroute response format. A traceroute response has a tr_query at the 61131087Smarcel * beginning, followed by one tr_resp for each hop taken. 62131087Smarcel */ 63131087Smarcelstruct tr_resp { 64131087Smarcel u_int32_t tr_qarr; /* query arrival time */ 65131087Smarcel u_int32_t tr_inaddr; /* incoming interface address */ 66131087Smarcel u_int32_t tr_outaddr; /* outgoing interface address */ 67131087Smarcel u_int32_t tr_rmtaddr; /* parent address in source tree */ 68131087Smarcel u_int32_t tr_vifin; /* input packet count on interface */ 69131087Smarcel u_int32_t tr_vifout; /* output packet count on interface */ 70131087Smarcel u_int32_t tr_pktcnt; /* total incoming packets for src-grp */ 71131087Smarcel u_int8_t tr_rproto; /* routing proto deployed on router */ 72131087Smarcel u_int8_t tr_fttl; /* ttl required to forward on outvif */ 73131087Smarcel u_int8_t tr_smask; /* subnet mask for src addr */ 74131087Smarcel u_int8_t tr_rflags; /* forwarding error codes */ 75131087Smarcel}; 76131087Smarcel 77131087Smarcel/* defs within mtrace */ 78131087Smarcel#define TR_QUERY 1 79131087Smarcel#define TR_RESP 2 80131087Smarcel 81131087Smarcel/* fields for tr_rflags (forwarding error codes) */ 82131087Smarcel#define TR_NO_ERR 0 83131087Smarcel#define TR_WRONG_IF 1 84131087Smarcel#define TR_PRUNED 2 85131087Smarcel#define TR_OPRUNED 3 86131087Smarcel#define TR_SCOPED 4 87131087Smarcel#define TR_NO_RTE 5 88131087Smarcel#define TR_NO_FWD 7 89131087Smarcel#define TR_NO_SPACE 0x81 90131087Smarcel#define TR_OLD_ROUTER 0x82 91131087Smarcel 92131087Smarcel/* fields for tr_rproto (routing protocol) */ 93131087Smarcel#define TR_PROTO_DVMRP 1 94131087Smarcel#define TR_PROTO_MOSPF 2 95131087Smarcel#define TR_PROTO_PIM 3 96131087Smarcel#define TR_PROTO_CBT 4 97131087Smarcel 98131087Smarcel/* igmpv3 report types */ 99131087Smarcelstatic struct tok igmpv3report2str[] = { 100131087Smarcel { 1, "is_in" }, 101131087Smarcel { 2, "is_ex" }, 102131087Smarcel { 3, "to_in" }, 103131087Smarcel { 4, "to_ex" }, 104131087Smarcel { 5, "allow" }, 105131087Smarcel { 6, "block" }, 106131087Smarcel { 0, NULL } 107131087Smarcel}; 108131087Smarcel 109131087Smarcelstatic void 110131087Smarcelprint_mtrace(register const u_char *bp, register u_int len) 111131087Smarcel{ 112131087Smarcel register const struct tr_query *tr = (const struct tr_query *)(bp + 8); 113131087Smarcel 114131087Smarcel TCHECK(*tr); 115131087Smarcel if (len < 8 + sizeof (struct tr_query)) { 116131087Smarcel (void)printf(" [invalid len %d]", len); 117131087Smarcel return; 118131087Smarcel } 119131087Smarcel printf("mtrace %u: %s to %s reply-to %s", 120131087Smarcel TR_GETQID(EXTRACT_32BITS(&tr->tr_rttlqid)), 121131087Smarcel ipaddr_string(&tr->tr_src), ipaddr_string(&tr->tr_dst), 122131087Smarcel ipaddr_string(&tr->tr_raddr)); 123131087Smarcel if (IN_CLASSD(EXTRACT_32BITS(&tr->tr_raddr))) 124131087Smarcel printf(" with-ttl %d", TR_GETTTL(EXTRACT_32BITS(&tr->tr_rttlqid))); 125131087Smarcel return; 126131087Smarceltrunc: 127131087Smarcel (void)printf("[|igmp]"); 128131087Smarcel return; 129131087Smarcel} 130131087Smarcel 131131087Smarcelstatic void 132131087Smarcelprint_mresp(register const u_char *bp, register u_int len) 133131087Smarcel{ 134131087Smarcel register const struct tr_query *tr = (const struct tr_query *)(bp + 8); 135131087Smarcel 136131087Smarcel TCHECK(*tr); 137131087Smarcel if (len < 8 + sizeof (struct tr_query)) { 138131087Smarcel (void)printf(" [invalid len %d]", len); 139131087Smarcel return; 140131087Smarcel } 141131087Smarcel printf("mresp %lu: %s to %s reply-to %s", 142131087Smarcel (u_long)TR_GETQID(EXTRACT_32BITS(&tr->tr_rttlqid)), 143131087Smarcel ipaddr_string(&tr->tr_src), ipaddr_string(&tr->tr_dst), 144131087Smarcel ipaddr_string(&tr->tr_raddr)); 145131087Smarcel if (IN_CLASSD(EXTRACT_32BITS(&tr->tr_raddr))) 146131087Smarcel printf(" with-ttl %d", TR_GETTTL(EXTRACT_32BITS(&tr->tr_rttlqid))); 147131087Smarcel return; 148131087Smarceltrunc: 149131087Smarcel (void)printf("[|igmp]"); 150131087Smarcel return; 151131087Smarcel} 152131087Smarcel 153131087Smarcelstatic void 154131087Smarcelprint_igmpv3_report(register const u_char *bp, register u_int len) 155131087Smarcel{ 156131087Smarcel u_int group, nsrcs, ngroups; 157131087Smarcel register u_int i, j; 158131087Smarcel 159131087Smarcel /* Minimum len is 16, and should be a multiple of 4 */ 160131087Smarcel if (len < 16 || len & 0x03) { 161131087Smarcel (void)printf(" [invalid len %d]", len); 162131087Smarcel return; 163131087Smarcel } 164131087Smarcel TCHECK2(bp[6], 2); 165131087Smarcel ngroups = EXTRACT_16BITS(&bp[6]); 166131087Smarcel (void)printf(", %d group record(s)", ngroups); 167131087Smarcel if (vflag > 0) { 168131087Smarcel /* Print the group records */ 169131087Smarcel group = 8; 170131087Smarcel for (i=0; i<ngroups; i++) { 171131087Smarcel if (len < group+8) { 172131087Smarcel (void)printf(" [invalid number of groups]"); 173131087Smarcel return; 174131087Smarcel } 175131087Smarcel TCHECK2(bp[group+4], 4); 176131087Smarcel (void)printf(" [gaddr %s", ipaddr_string(&bp[group+4])); 177138383Smarcel (void)printf(" %s", tok2str(igmpv3report2str, " [v3-report-#%d]", 178131087Smarcel bp[group])); 179138383Smarcel nsrcs = EXTRACT_16BITS(&bp[group+2]); 180131087Smarcel /* Check the number of sources and print them */ 181131087Smarcel if (len < group+8+(nsrcs<<2)) { 182131087Smarcel (void)printf(" [invalid number of sources %d]", nsrcs); 183131087Smarcel return; 184131087Smarcel } 185131087Smarcel if (vflag == 1) 186131087Smarcel (void)printf(", %d source(s)", nsrcs); 187131087Smarcel else { 188131087Smarcel /* Print the sources */ 189131087Smarcel (void)printf(" {"); 190131087Smarcel for (j=0; j<nsrcs; j++) { 191131087Smarcel TCHECK2(bp[group+8+(j<<2)], 4); 192131087Smarcel (void)printf(" %s", ipaddr_string(&bp[group+8+(j<<2)])); 193131087Smarcel } 194131087Smarcel (void)printf(" }"); 195131087Smarcel } 196131087Smarcel /* Next group record */ 197131087Smarcel group += 8 + (nsrcs << 2); 198131087Smarcel (void)printf("]"); 199131087Smarcel } 200131087Smarcel } 201131087Smarcel return; 202131087Smarceltrunc: 203131087Smarcel (void)printf("[|igmp]"); 204131087Smarcel return; 205131087Smarcel} 206131087Smarcel 207131087Smarcelstatic void 208131087Smarcelprint_igmpv3_query(register const u_char *bp, register u_int len) 209131087Smarcel{ 210131087Smarcel u_int mrc; 211131087Smarcel int mrt; 212131087Smarcel u_int nsrcs; 213131087Smarcel register u_int i; 214131087Smarcel 215131087Smarcel (void)printf(" v3"); 216131087Smarcel /* Minimum len is 12, and should be a multiple of 4 */ 217131087Smarcel if (len < 12 || len & 0x03) { 218131087Smarcel (void)printf(" [invalid len %d]", len); 219131087Smarcel return; 220131087Smarcel } 221131087Smarcel TCHECK(bp[1]); 222131087Smarcel mrc = bp[1]; 223131087Smarcel if (mrc < 128) { 224131087Smarcel mrt = mrc; 225131087Smarcel } else { 226131087Smarcel mrt = ((mrc & 0x0f) | 0x10) << (((mrc & 0x70) >> 4) + 3); 227131087Smarcel } 228131087Smarcel if (mrc != 100) { 229131087Smarcel (void)printf(" [max resp time "); 230131087Smarcel if (mrt < 600) { 231131087Smarcel (void)printf("%.1fs", mrt * 0.1); 232131087Smarcel } else { 233131087Smarcel relts_print(mrt / 10); 234131087Smarcel } 235131087Smarcel (void)printf("]"); 236131087Smarcel } 237131087Smarcel TCHECK2(bp[4], 4); 238131087Smarcel if (EXTRACT_32BITS(&bp[4]) == 0) 239131087Smarcel return; 240131087Smarcel (void)printf(" [gaddr %s", ipaddr_string(&bp[4])); 241131087Smarcel TCHECK2(bp[10], 2); 242131087Smarcel nsrcs = EXTRACT_16BITS(&bp[10]); 243131087Smarcel if (nsrcs > 0) { 244131087Smarcel if (len < 12 + (nsrcs << 2)) 245131087Smarcel (void)printf(" [invalid number of sources]"); 246131087Smarcel else if (vflag > 1) { 247131087Smarcel (void)printf(" {"); 248131087Smarcel for (i=0; i<nsrcs; i++) { 249131087Smarcel TCHECK2(bp[12+(i<<2)], 4); 250131087Smarcel (void)printf(" %s", ipaddr_string(&bp[12+(i<<2)])); 251131087Smarcel } 252131087Smarcel (void)printf(" }"); 253131087Smarcel } else 254131087Smarcel (void)printf(", %d source(s)", nsrcs); 255131087Smarcel } 256131087Smarcel (void)printf("]"); 257131087Smarcel return; 258131087Smarceltrunc: 259131087Smarcel (void)printf("[|igmp]"); 260131087Smarcel return; 261131087Smarcel} 262131087Smarcel 263131087Smarcelvoid 264131087Smarceligmp_print(register const u_char *bp, register u_int len) 265131087Smarcel{ 266131087Smarcel struct cksum_vec vec[1]; 267131087Smarcel 268131087Smarcel if (qflag) { 269131087Smarcel (void)printf("igmp"); 270131087Smarcel return; 271131087Smarcel } 272131087Smarcel 273131087Smarcel TCHECK(bp[0]); 274131087Smarcel switch (bp[0]) { 275131087Smarcel case 0x11: 276131087Smarcel (void)printf("igmp query"); 277131087Smarcel if (len >= 12) 278131087Smarcel print_igmpv3_query(bp, len); 279131087Smarcel else { 280131087Smarcel TCHECK(bp[1]); 281131087Smarcel if (bp[1]) { 282131087Smarcel (void)printf(" v2"); 283131087Smarcel if (bp[1] != 100) 284131087Smarcel (void)printf(" [max resp time %d]", bp[1]); 285131087Smarcel } else 286131087Smarcel (void)printf(" v1"); 287131087Smarcel TCHECK2(bp[4], 4); 288131087Smarcel if (EXTRACT_32BITS(&bp[4])) 289131087Smarcel (void)printf(" [gaddr %s]", ipaddr_string(&bp[4])); 290131087Smarcel if (len != 8) 291131087Smarcel (void)printf(" [len %d]", len); 292131087Smarcel } 293131087Smarcel break; 294131087Smarcel case 0x12: 295131087Smarcel TCHECK2(bp[4], 4); 296131087Smarcel (void)printf("igmp v1 report %s", ipaddr_string(&bp[4])); 297131087Smarcel if (len != 8) 298131087Smarcel (void)printf(" [len %d]", len); 299131087Smarcel break; 300131087Smarcel case 0x16: 301131087Smarcel TCHECK2(bp[4], 4); 302131087Smarcel (void)printf("igmp v2 report %s", ipaddr_string(&bp[4])); 303131087Smarcel break; 304131087Smarcel case 0x22: 305131087Smarcel (void)printf("igmp v3 report"); 306131087Smarcel print_igmpv3_report(bp, len); 307131087Smarcel break; 308131087Smarcel case 0x17: 309131087Smarcel TCHECK2(bp[4], 4); 310131087Smarcel (void)printf("igmp leave %s", ipaddr_string(&bp[4])); 311131087Smarcel break; 312131087Smarcel case 0x13: 313131087Smarcel (void)printf("igmp dvmrp"); 314131087Smarcel if (len < 8) 315131087Smarcel (void)printf(" [len %d]", len); 316131087Smarcel else 317131087Smarcel dvmrp_print(bp, len); 318131087Smarcel break; 319131087Smarcel case 0x14: 320131087Smarcel (void)printf("igmp pimv1"); 321131087Smarcel pimv1_print(bp, len); 322131087Smarcel break; 323131087Smarcel case 0x1e: 324131087Smarcel print_mresp(bp, len); 325131087Smarcel break; 326131087Smarcel case 0x1f: 327131087Smarcel print_mtrace(bp, len); 328131087Smarcel break; 329131087Smarcel default: 330131087Smarcel (void)printf("igmp-%d", bp[0]); 331131087Smarcel break; 332131087Smarcel } 333131087Smarcel 334131087Smarcel if (vflag && TTEST2(bp[0], len)) { 335131087Smarcel /* Check the IGMP checksum */ 336131087Smarcel vec[0].ptr = bp; 337131087Smarcel vec[0].len = len; 338131087Smarcel if (in_cksum(vec, 1)) 339131087Smarcel printf(" bad igmp cksum %x!", EXTRACT_16BITS(&bp[2])); 340131087Smarcel } 341131087Smarcel return; 342131087Smarceltrunc: 343131087Smarcel fputs("[|igmp]", stdout); 344131087Smarcel} 345131087Smarcel