1685295f4SBill Fenner /* 2685295f4SBill Fenner * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 3685295f4SBill Fenner * The Regents of the University of California. All rights reserved. 4685295f4SBill Fenner * 5685295f4SBill Fenner * Redistribution and use in source and binary forms, with or without 6685295f4SBill Fenner * modification, are permitted provided that: (1) source code distributions 7685295f4SBill Fenner * retain the above copyright notice and this paragraph in its entirety, (2) 8685295f4SBill Fenner * distributions including binary code include the above copyright notice and 9685295f4SBill Fenner * this paragraph in its entirety in the documentation or other materials 10685295f4SBill Fenner * provided with the distribution, and (3) all advertising materials mentioning 11685295f4SBill Fenner * features or use of this software display the following acknowledgement: 12685295f4SBill Fenner * ``This product includes software developed by the University of California, 13685295f4SBill Fenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14685295f4SBill Fenner * the University nor the names of its contributors may be used to endorse 15685295f4SBill Fenner * or promote products derived from this software without specific prior 16685295f4SBill Fenner * written permission. 17685295f4SBill Fenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18685295f4SBill Fenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19685295f4SBill Fenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20685295f4SBill Fenner */ 21685295f4SBill Fenner 223340d773SGleb Smirnoff /* \summary: Internet Group Management Protocol (IGMP) printer */ 233340d773SGleb Smirnoff 24*ee67461eSJoseph Mingrone /* 25*ee67461eSJoseph Mingrone * specification: 26*ee67461eSJoseph Mingrone * 27*ee67461eSJoseph Mingrone * RFC 2236 for IGMPv2 28*ee67461eSJoseph Mingrone * RFC 3376 for IGMPv3 29*ee67461eSJoseph Mingrone * draft-asaeda-mboned-mtrace-v2 for the mtrace message 30*ee67461eSJoseph Mingrone */ 31*ee67461eSJoseph Mingrone 32*ee67461eSJoseph Mingrone #include <config.h> 33685295f4SBill Fenner 34*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h" 35685295f4SBill Fenner 363340d773SGleb Smirnoff #include "netdissect.h" 37685295f4SBill Fenner #include "addrtoname.h" 383340d773SGleb Smirnoff #include "extract.h" 39685295f4SBill Fenner 40685295f4SBill Fenner #ifndef IN_CLASSD 41685295f4SBill Fenner #define IN_CLASSD(i) (((int32_t)(i) & 0xf0000000) == 0xe0000000) 42685295f4SBill Fenner #endif 43685295f4SBill Fenner 443c602fabSXin LI 45685295f4SBill Fenner /* (following from ipmulti/mrouted/prune.h) */ 46685295f4SBill Fenner 47685295f4SBill Fenner /* 48685295f4SBill Fenner * The packet format for a traceroute request. 49685295f4SBill Fenner */ 50685295f4SBill Fenner struct tr_query { 51*ee67461eSJoseph Mingrone nd_uint32_t tr_src; /* traceroute source */ 52*ee67461eSJoseph Mingrone nd_uint32_t tr_dst; /* traceroute destination */ 53*ee67461eSJoseph Mingrone nd_uint32_t tr_raddr; /* traceroute response address */ 54*ee67461eSJoseph Mingrone nd_uint8_t tr_rttl; /* response ttl */ 55*ee67461eSJoseph Mingrone nd_uint24_t tr_qid; /* qid */ 56685295f4SBill Fenner }; 57685295f4SBill Fenner 58685295f4SBill Fenner /* 59685295f4SBill Fenner * Traceroute response format. A traceroute response has a tr_query at the 60685295f4SBill Fenner * beginning, followed by one tr_resp for each hop taken. 61685295f4SBill Fenner */ 62685295f4SBill Fenner struct tr_resp { 63*ee67461eSJoseph Mingrone nd_uint32_t tr_qarr; /* query arrival time */ 64*ee67461eSJoseph Mingrone nd_uint32_t tr_inaddr; /* incoming interface address */ 65*ee67461eSJoseph Mingrone nd_uint32_t tr_outaddr; /* outgoing interface address */ 66*ee67461eSJoseph Mingrone nd_uint32_t tr_rmtaddr; /* parent address in source tree */ 67*ee67461eSJoseph Mingrone nd_uint32_t tr_vifin; /* input packet count on interface */ 68*ee67461eSJoseph Mingrone nd_uint32_t tr_vifout; /* output packet count on interface */ 69*ee67461eSJoseph Mingrone nd_uint32_t tr_pktcnt; /* total incoming packets for src-grp */ 70*ee67461eSJoseph Mingrone nd_uint8_t tr_rproto; /* routing proto deployed on router */ 71*ee67461eSJoseph Mingrone nd_uint8_t tr_fttl; /* ttl required to forward on outvif */ 72*ee67461eSJoseph Mingrone nd_uint8_t tr_smask; /* subnet mask for src addr */ 73*ee67461eSJoseph Mingrone nd_uint8_t tr_rflags; /* forwarding error codes */ 74685295f4SBill Fenner }; 75685295f4SBill Fenner 76685295f4SBill Fenner /* defs within mtrace */ 77685295f4SBill Fenner #define TR_QUERY 1 78685295f4SBill Fenner #define TR_RESP 2 79685295f4SBill Fenner 80685295f4SBill Fenner /* fields for tr_rflags (forwarding error codes) */ 81685295f4SBill Fenner #define TR_NO_ERR 0 82685295f4SBill Fenner #define TR_WRONG_IF 1 83685295f4SBill Fenner #define TR_PRUNED 2 84685295f4SBill Fenner #define TR_OPRUNED 3 85685295f4SBill Fenner #define TR_SCOPED 4 86685295f4SBill Fenner #define TR_NO_RTE 5 87685295f4SBill Fenner #define TR_NO_FWD 7 88685295f4SBill Fenner #define TR_NO_SPACE 0x81 89685295f4SBill Fenner #define TR_OLD_ROUTER 0x82 90685295f4SBill Fenner 91685295f4SBill Fenner /* fields for tr_rproto (routing protocol) */ 92685295f4SBill Fenner #define TR_PROTO_DVMRP 1 93685295f4SBill Fenner #define TR_PROTO_MOSPF 2 94685295f4SBill Fenner #define TR_PROTO_PIM 3 95685295f4SBill Fenner #define TR_PROTO_CBT 4 96685295f4SBill Fenner 97685295f4SBill Fenner /* igmpv3 report types */ 983c602fabSXin LI static const struct tok igmpv3report2str[] = { 99685295f4SBill Fenner { 1, "is_in" }, 100685295f4SBill Fenner { 2, "is_ex" }, 101685295f4SBill Fenner { 3, "to_in" }, 102685295f4SBill Fenner { 4, "to_ex" }, 103685295f4SBill Fenner { 5, "allow" }, 104685295f4SBill Fenner { 6, "block" }, 105685295f4SBill Fenner { 0, NULL } 106685295f4SBill Fenner }; 107685295f4SBill Fenner 108685295f4SBill Fenner static void 1093c602fabSXin LI print_mtrace(netdissect_options *ndo, 110*ee67461eSJoseph Mingrone const char *typename, 111*ee67461eSJoseph Mingrone const u_char *bp, u_int len) 112685295f4SBill Fenner { 113*ee67461eSJoseph Mingrone const struct tr_query *tr = (const struct tr_query *)(bp + 8); 114685295f4SBill Fenner 1155b0fe478SBruce M Simpson if (len < 8 + sizeof (struct tr_query)) { 116*ee67461eSJoseph Mingrone ND_PRINT(" [invalid len %u]", len); 1175b0fe478SBruce M Simpson return; 1185b0fe478SBruce M Simpson } 119*ee67461eSJoseph Mingrone ND_PRINT("%s %u: %s to %s reply-to %s", 120*ee67461eSJoseph Mingrone typename, 121*ee67461eSJoseph Mingrone GET_BE_U_3(tr->tr_qid), 122*ee67461eSJoseph Mingrone GET_IPADDR_STRING(tr->tr_src), GET_IPADDR_STRING(tr->tr_dst), 123*ee67461eSJoseph Mingrone GET_IPADDR_STRING(tr->tr_raddr)); 124*ee67461eSJoseph Mingrone if (IN_CLASSD(GET_BE_U_4(tr->tr_raddr))) 125*ee67461eSJoseph Mingrone ND_PRINT(" with-ttl %u", GET_U_1(tr->tr_rttl)); 126685295f4SBill Fenner } 127685295f4SBill Fenner 128685295f4SBill Fenner static void 1293c602fabSXin LI print_igmpv3_report(netdissect_options *ndo, 130*ee67461eSJoseph Mingrone const u_char *bp, u_int len) 131685295f4SBill Fenner { 132a90e161bSBill Fenner u_int group, nsrcs, ngroups; 133*ee67461eSJoseph Mingrone u_int i, j; 134685295f4SBill Fenner 135685295f4SBill Fenner /* Minimum len is 16, and should be a multiple of 4 */ 136685295f4SBill Fenner if (len < 16 || len & 0x03) { 137*ee67461eSJoseph Mingrone ND_PRINT(" [invalid len %u]", len); 138685295f4SBill Fenner return; 139685295f4SBill Fenner } 140*ee67461eSJoseph Mingrone ngroups = GET_BE_U_2(bp + 6); 141*ee67461eSJoseph Mingrone ND_PRINT(", %u group record(s)", ngroups); 1423c602fabSXin LI if (ndo->ndo_vflag > 0) { 143685295f4SBill Fenner /* Print the group records */ 144685295f4SBill Fenner group = 8; 145685295f4SBill Fenner for (i=0; i<ngroups; i++) { 146685295f4SBill Fenner if (len < group+8) { 147*ee67461eSJoseph Mingrone ND_PRINT(" [invalid number of groups]"); 148685295f4SBill Fenner return; 149685295f4SBill Fenner } 150*ee67461eSJoseph Mingrone ND_PRINT(" [gaddr %s", GET_IPADDR_STRING(bp + group + 4)); 151*ee67461eSJoseph Mingrone ND_PRINT(" %s", tok2str(igmpv3report2str, " [v3-report-#%u]", 152*ee67461eSJoseph Mingrone GET_U_1(bp + group))); 153*ee67461eSJoseph Mingrone nsrcs = GET_BE_U_2(bp + group + 2); 154685295f4SBill Fenner /* Check the number of sources and print them */ 155685295f4SBill Fenner if (len < group+8+(nsrcs<<2)) { 156*ee67461eSJoseph Mingrone ND_PRINT(" [invalid number of sources %u]", nsrcs); 157685295f4SBill Fenner return; 158685295f4SBill Fenner } 1593c602fabSXin LI if (ndo->ndo_vflag == 1) 160*ee67461eSJoseph Mingrone ND_PRINT(", %u source(s)", nsrcs); 161685295f4SBill Fenner else { 162685295f4SBill Fenner /* Print the sources */ 163*ee67461eSJoseph Mingrone ND_PRINT(" {"); 164685295f4SBill Fenner for (j=0; j<nsrcs; j++) { 165*ee67461eSJoseph Mingrone ND_PRINT(" %s", GET_IPADDR_STRING(bp + group + 8 + (j << 2))); 166685295f4SBill Fenner } 167*ee67461eSJoseph Mingrone ND_PRINT(" }"); 168685295f4SBill Fenner } 169685295f4SBill Fenner /* Next group record */ 170685295f4SBill Fenner group += 8 + (nsrcs << 2); 171*ee67461eSJoseph Mingrone ND_PRINT("]"); 172685295f4SBill Fenner } 173685295f4SBill Fenner } 174685295f4SBill Fenner } 175685295f4SBill Fenner 176685295f4SBill Fenner static void 1773c602fabSXin LI print_igmpv3_query(netdissect_options *ndo, 178*ee67461eSJoseph Mingrone const u_char *bp, u_int len) 179685295f4SBill Fenner { 180a90e161bSBill Fenner u_int mrc; 1813340d773SGleb Smirnoff u_int mrt; 182a90e161bSBill Fenner u_int nsrcs; 183*ee67461eSJoseph Mingrone u_int i; 184685295f4SBill Fenner 185*ee67461eSJoseph Mingrone ND_PRINT(" v3"); 186685295f4SBill Fenner /* Minimum len is 12, and should be a multiple of 4 */ 187685295f4SBill Fenner if (len < 12 || len & 0x03) { 188*ee67461eSJoseph Mingrone ND_PRINT(" [invalid len %u]", len); 189685295f4SBill Fenner return; 190685295f4SBill Fenner } 191*ee67461eSJoseph Mingrone mrc = GET_U_1(bp + 1); 192a90e161bSBill Fenner if (mrc < 128) { 193a90e161bSBill Fenner mrt = mrc; 194a90e161bSBill Fenner } else { 195a90e161bSBill Fenner mrt = ((mrc & 0x0f) | 0x10) << (((mrc & 0x70) >> 4) + 3); 196a90e161bSBill Fenner } 197a90e161bSBill Fenner if (mrc != 100) { 198*ee67461eSJoseph Mingrone ND_PRINT(" [max resp time "); 199d09a7e67SXin LI if (mrt < 600) { 200*ee67461eSJoseph Mingrone ND_PRINT("%.1fs", mrt * 0.1); 201d09a7e67SXin LI } else { 2023340d773SGleb Smirnoff unsigned_relts_print(ndo, mrt / 10); 203d09a7e67SXin LI } 204*ee67461eSJoseph Mingrone ND_PRINT("]"); 205a90e161bSBill Fenner } 206*ee67461eSJoseph Mingrone if (GET_BE_U_4(bp + 4) == 0) 207685295f4SBill Fenner return; 208*ee67461eSJoseph Mingrone ND_PRINT(" [gaddr %s", GET_IPADDR_STRING(bp + 4)); 209*ee67461eSJoseph Mingrone nsrcs = GET_BE_U_2(bp + 10); 210685295f4SBill Fenner if (nsrcs > 0) { 211685295f4SBill Fenner if (len < 12 + (nsrcs << 2)) 212*ee67461eSJoseph Mingrone ND_PRINT(" [invalid number of sources]"); 2133c602fabSXin LI else if (ndo->ndo_vflag > 1) { 214*ee67461eSJoseph Mingrone ND_PRINT(" {"); 215685295f4SBill Fenner for (i=0; i<nsrcs; i++) { 216*ee67461eSJoseph Mingrone ND_PRINT(" %s", GET_IPADDR_STRING(bp + 12 + (i << 2))); 217685295f4SBill Fenner } 218*ee67461eSJoseph Mingrone ND_PRINT(" }"); 219685295f4SBill Fenner } else 220*ee67461eSJoseph Mingrone ND_PRINT(", %u source(s)", nsrcs); 221685295f4SBill Fenner } 222*ee67461eSJoseph Mingrone ND_PRINT("]"); 223685295f4SBill Fenner } 224685295f4SBill Fenner 225685295f4SBill Fenner void 2263c602fabSXin LI igmp_print(netdissect_options *ndo, 227*ee67461eSJoseph Mingrone const u_char *bp, u_int len) 228685295f4SBill Fenner { 229cac3dcd5SXin LI struct cksum_vec vec[1]; 230cac3dcd5SXin LI 231*ee67461eSJoseph Mingrone ndo->ndo_protocol = "igmp"; 2323c602fabSXin LI if (ndo->ndo_qflag) { 233*ee67461eSJoseph Mingrone ND_PRINT("igmp"); 234685295f4SBill Fenner return; 235685295f4SBill Fenner } 236685295f4SBill Fenner 237*ee67461eSJoseph Mingrone switch (GET_U_1(bp)) { 238685295f4SBill Fenner case 0x11: 239*ee67461eSJoseph Mingrone ND_PRINT("igmp query"); 240685295f4SBill Fenner if (len >= 12) 2413c602fabSXin LI print_igmpv3_query(ndo, bp, len); 242685295f4SBill Fenner else { 243*ee67461eSJoseph Mingrone if (GET_U_1(bp + 1)) { 244*ee67461eSJoseph Mingrone ND_PRINT(" v2"); 245*ee67461eSJoseph Mingrone if (GET_U_1(bp + 1) != 100) 246*ee67461eSJoseph Mingrone ND_PRINT(" [max resp time %u]", GET_U_1(bp + 1)); 247685295f4SBill Fenner } else 248*ee67461eSJoseph Mingrone ND_PRINT(" v1"); 249*ee67461eSJoseph Mingrone if (GET_BE_U_4(bp + 4)) 250*ee67461eSJoseph Mingrone ND_PRINT(" [gaddr %s]", GET_IPADDR_STRING(bp + 4)); 251685295f4SBill Fenner if (len != 8) 252*ee67461eSJoseph Mingrone ND_PRINT(" [len %u]", len); 253685295f4SBill Fenner } 254685295f4SBill Fenner break; 255685295f4SBill Fenner case 0x12: 256*ee67461eSJoseph Mingrone ND_PRINT("igmp v1 report %s", GET_IPADDR_STRING(bp + 4)); 257685295f4SBill Fenner if (len != 8) 258*ee67461eSJoseph Mingrone ND_PRINT(" [len %u]", len); 259685295f4SBill Fenner break; 260685295f4SBill Fenner case 0x16: 261*ee67461eSJoseph Mingrone ND_PRINT("igmp v2 report %s", GET_IPADDR_STRING(bp + 4)); 262685295f4SBill Fenner break; 263685295f4SBill Fenner case 0x22: 264*ee67461eSJoseph Mingrone ND_PRINT("igmp v3 report"); 2653c602fabSXin LI print_igmpv3_report(ndo, bp, len); 266685295f4SBill Fenner break; 267685295f4SBill Fenner case 0x17: 268*ee67461eSJoseph Mingrone ND_PRINT("igmp leave %s", GET_IPADDR_STRING(bp + 4)); 269685295f4SBill Fenner break; 270685295f4SBill Fenner case 0x13: 271*ee67461eSJoseph Mingrone ND_PRINT("igmp dvmrp"); 272685295f4SBill Fenner if (len < 8) 273*ee67461eSJoseph Mingrone ND_PRINT(" [len %u]", len); 274685295f4SBill Fenner else 2753c602fabSXin LI dvmrp_print(ndo, bp, len); 276685295f4SBill Fenner break; 277685295f4SBill Fenner case 0x14: 278*ee67461eSJoseph Mingrone ND_PRINT("igmp pimv1"); 2793c602fabSXin LI pimv1_print(ndo, bp, len); 280685295f4SBill Fenner break; 281685295f4SBill Fenner case 0x1e: 282*ee67461eSJoseph Mingrone print_mtrace(ndo, "mresp", bp, len); 283685295f4SBill Fenner break; 284685295f4SBill Fenner case 0x1f: 285*ee67461eSJoseph Mingrone print_mtrace(ndo, "mtrace", bp, len); 286685295f4SBill Fenner break; 287685295f4SBill Fenner default: 288*ee67461eSJoseph Mingrone ND_PRINT("igmp-%u", GET_U_1(bp)); 289685295f4SBill Fenner break; 290685295f4SBill Fenner } 291685295f4SBill Fenner 292*ee67461eSJoseph Mingrone if (ndo->ndo_vflag && len >= 4 && ND_TTEST_LEN(bp, len)) { 293685295f4SBill Fenner /* Check the IGMP checksum */ 294cac3dcd5SXin LI vec[0].ptr = bp; 295cac3dcd5SXin LI vec[0].len = len; 296cac3dcd5SXin LI if (in_cksum(vec, 1)) 297*ee67461eSJoseph Mingrone ND_PRINT(" bad igmp cksum %x!", GET_BE_U_2(bp + 2)); 298685295f4SBill Fenner } 299685295f4SBill Fenner } 300