print-igmp.c revision 1.8
1/* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 22#include <sys/cdefs.h> 23#ifndef lint 24__RCSID("$NetBSD: print-igmp.c,v 1.8 2020/02/24 18:39:47 kamil Exp $"); 25#endif 26 27/* \summary: Internet Group Management Protocol (IGMP) printer */ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include <netdissect-stdinc.h> 34 35#include "netdissect.h" 36#include "addrtoname.h" 37#include "extract.h" 38 39#ifndef IN_CLASSD 40#define IN_CLASSD(i) (((int32_t)(i) & 0xf0000000) == 0xe0000000) 41#endif 42 43static const char tstr[] = "[|igmp]"; 44 45/* (following from ipmulti/mrouted/prune.h) */ 46 47/* 48 * The packet format for a traceroute request. 49 */ 50struct tr_query { 51 uint32_t tr_src; /* traceroute source */ 52 uint32_t tr_dst; /* traceroute destination */ 53 uint32_t tr_raddr; /* traceroute response address */ 54 uint32_t tr_rttlqid; /* response ttl and qid */ 55}; 56 57#define TR_GETTTL(x) (int)(((x) >> 24) & 0xff) 58#define TR_GETQID(x) ((x) & 0x00ffffff) 59 60/* 61 * Traceroute response format. A traceroute response has a tr_query at the 62 * beginning, followed by one tr_resp for each hop taken. 63 */ 64struct tr_resp { 65 uint32_t tr_qarr; /* query arrival time */ 66 uint32_t tr_inaddr; /* incoming interface address */ 67 uint32_t tr_outaddr; /* outgoing interface address */ 68 uint32_t tr_rmtaddr; /* parent address in source tree */ 69 uint32_t tr_vifin; /* input packet count on interface */ 70 uint32_t tr_vifout; /* output packet count on interface */ 71 uint32_t tr_pktcnt; /* total incoming packets for src-grp */ 72 uint8_t tr_rproto; /* routing proto deployed on router */ 73 uint8_t tr_fttl; /* ttl required to forward on outvif */ 74 uint8_t tr_smask; /* subnet mask for src addr */ 75 uint8_t tr_rflags; /* forwarding error codes */ 76}; 77 78/* defs within mtrace */ 79#define TR_QUERY 1 80#define TR_RESP 2 81 82/* fields for tr_rflags (forwarding error codes) */ 83#define TR_NO_ERR 0 84#define TR_WRONG_IF 1 85#define TR_PRUNED 2 86#define TR_OPRUNED 3 87#define TR_SCOPED 4 88#define TR_NO_RTE 5 89#define TR_NO_FWD 7 90#define TR_NO_SPACE 0x81 91#define TR_OLD_ROUTER 0x82 92 93/* fields for tr_rproto (routing protocol) */ 94#define TR_PROTO_DVMRP 1 95#define TR_PROTO_MOSPF 2 96#define TR_PROTO_PIM 3 97#define TR_PROTO_CBT 4 98 99/* igmpv3 report types */ 100static const struct tok igmpv3report2str[] = { 101 { 1, "is_in" }, 102 { 2, "is_ex" }, 103 { 3, "to_in" }, 104 { 4, "to_ex" }, 105 { 5, "allow" }, 106 { 6, "block" }, 107 { 0, NULL } 108}; 109 110UNALIGNED_OK 111static void 112print_mtrace(netdissect_options *ndo, 113 register const u_char *bp, register u_int len) 114{ 115 register const struct tr_query *tr = (const struct tr_query *)(bp + 8); 116 117 ND_TCHECK(*tr); 118 if (len < 8 + sizeof (struct tr_query)) { 119 ND_PRINT((ndo, " [invalid len %d]", len)); 120 return; 121 } 122 ND_PRINT((ndo, "mtrace %u: %s to %s reply-to %s", 123 TR_GETQID(EXTRACT_32BITS(&tr->tr_rttlqid)), 124 ipaddr_string(ndo, &tr->tr_src), ipaddr_string(ndo, &tr->tr_dst), 125 ipaddr_string(ndo, &tr->tr_raddr))); 126 if (IN_CLASSD(EXTRACT_32BITS(&tr->tr_raddr))) 127 ND_PRINT((ndo, " with-ttl %d", TR_GETTTL(EXTRACT_32BITS(&tr->tr_rttlqid)))); 128 return; 129trunc: 130 ND_PRINT((ndo, "%s", tstr)); 131} 132 133static void 134print_mresp(netdissect_options *ndo, 135 register const u_char *bp, register u_int len) 136{ 137 register const struct tr_query *tr = (const struct tr_query *)(bp + 8); 138 139 ND_TCHECK(*tr); 140 if (len < 8 + sizeof (struct tr_query)) { 141 ND_PRINT((ndo, " [invalid len %d]", len)); 142 return; 143 } 144 ND_PRINT((ndo, "mresp %lu: %s to %s reply-to %s", 145 (u_long)TR_GETQID(EXTRACT_32BITS(&tr->tr_rttlqid)), 146 ipaddr_string(ndo, &tr->tr_src), ipaddr_string(ndo, &tr->tr_dst), 147 ipaddr_string(ndo, &tr->tr_raddr))); 148 if (IN_CLASSD(EXTRACT_32BITS(&tr->tr_raddr))) 149 ND_PRINT((ndo, " with-ttl %d", TR_GETTTL(EXTRACT_32BITS(&tr->tr_rttlqid)))); 150 return; 151trunc: 152 ND_PRINT((ndo, "%s", tstr)); 153} 154 155static void 156print_igmpv3_report(netdissect_options *ndo, 157 register const u_char *bp, register u_int len) 158{ 159 u_int group, nsrcs, ngroups; 160 register u_int i, j; 161 162 /* Minimum len is 16, and should be a multiple of 4 */ 163 if (len < 16 || len & 0x03) { 164 ND_PRINT((ndo, " [invalid len %d]", len)); 165 return; 166 } 167 ND_TCHECK2(bp[6], 2); 168 ngroups = EXTRACT_16BITS(&bp[6]); 169 ND_PRINT((ndo, ", %d group record(s)", ngroups)); 170 if (ndo->ndo_vflag > 0) { 171 /* Print the group records */ 172 group = 8; 173 for (i=0; i<ngroups; i++) { 174 if (len < group+8) { 175 ND_PRINT((ndo, " [invalid number of groups]")); 176 return; 177 } 178 ND_TCHECK2(bp[group+4], 4); 179 ND_PRINT((ndo, " [gaddr %s", ipaddr_string(ndo, &bp[group+4]))); 180 ND_PRINT((ndo, " %s", tok2str(igmpv3report2str, " [v3-report-#%d]", 181 bp[group]))); 182 nsrcs = EXTRACT_16BITS(&bp[group+2]); 183 /* Check the number of sources and print them */ 184 if (len < group+8+(nsrcs<<2)) { 185 ND_PRINT((ndo, " [invalid number of sources %d]", nsrcs)); 186 return; 187 } 188 if (ndo->ndo_vflag == 1) 189 ND_PRINT((ndo, ", %d source(s)", nsrcs)); 190 else { 191 /* Print the sources */ 192 ND_PRINT((ndo, " {")); 193 for (j=0; j<nsrcs; j++) { 194 ND_TCHECK2(bp[group+8+(j<<2)], 4); 195 ND_PRINT((ndo, " %s", ipaddr_string(ndo, &bp[group+8+(j<<2)]))); 196 } 197 ND_PRINT((ndo, " }")); 198 } 199 /* Next group record */ 200 group += 8 + (nsrcs << 2); 201 ND_PRINT((ndo, "]")); 202 } 203 } 204 return; 205trunc: 206 ND_PRINT((ndo, "%s", tstr)); 207} 208 209static void 210print_igmpv3_query(netdissect_options *ndo, 211 register const u_char *bp, register u_int len) 212{ 213 u_int mrc; 214 u_int mrt; 215 u_int nsrcs; 216 register u_int i; 217 218 ND_PRINT((ndo, " v3")); 219 /* Minimum len is 12, and should be a multiple of 4 */ 220 if (len < 12 || len & 0x03) { 221 ND_PRINT((ndo, " [invalid len %d]", len)); 222 return; 223 } 224 ND_TCHECK(bp[1]); 225 mrc = bp[1]; 226 if (mrc < 128) { 227 mrt = mrc; 228 } else { 229 mrt = ((mrc & 0x0f) | 0x10) << (((mrc & 0x70) >> 4) + 3); 230 } 231 if (mrc != 100) { 232 ND_PRINT((ndo, " [max resp time ")); 233 if (mrt < 600) { 234 ND_PRINT((ndo, "%.1fs", mrt * 0.1)); 235 } else { 236 unsigned_relts_print(ndo, mrt / 10); 237 } 238 ND_PRINT((ndo, "]")); 239 } 240 ND_TCHECK2(bp[4], 4); 241 if (EXTRACT_32BITS(&bp[4]) == 0) 242 return; 243 ND_PRINT((ndo, " [gaddr %s", ipaddr_string(ndo, &bp[4]))); 244 ND_TCHECK2(bp[10], 2); 245 nsrcs = EXTRACT_16BITS(&bp[10]); 246 if (nsrcs > 0) { 247 if (len < 12 + (nsrcs << 2)) 248 ND_PRINT((ndo, " [invalid number of sources]")); 249 else if (ndo->ndo_vflag > 1) { 250 ND_PRINT((ndo, " {")); 251 for (i=0; i<nsrcs; i++) { 252 ND_TCHECK2(bp[12+(i<<2)], 4); 253 ND_PRINT((ndo, " %s", ipaddr_string(ndo, &bp[12+(i<<2)]))); 254 } 255 ND_PRINT((ndo, " }")); 256 } else 257 ND_PRINT((ndo, ", %d source(s)", nsrcs)); 258 } 259 ND_PRINT((ndo, "]")); 260 return; 261trunc: 262 ND_PRINT((ndo, "%s", tstr)); 263} 264 265void 266igmp_print(netdissect_options *ndo, 267 register const u_char *bp, register u_int len) 268{ 269 struct cksum_vec vec[1]; 270 271 if (ndo->ndo_qflag) { 272 ND_PRINT((ndo, "igmp")); 273 return; 274 } 275 276 ND_TCHECK(bp[0]); 277 switch (bp[0]) { 278 case 0x11: 279 ND_PRINT((ndo, "igmp query")); 280 if (len >= 12) 281 print_igmpv3_query(ndo, bp, len); 282 else { 283 ND_TCHECK(bp[1]); 284 if (bp[1]) { 285 ND_PRINT((ndo, " v2")); 286 if (bp[1] != 100) 287 ND_PRINT((ndo, " [max resp time %d]", bp[1])); 288 } else 289 ND_PRINT((ndo, " v1")); 290 ND_TCHECK2(bp[4], 4); 291 if (EXTRACT_32BITS(&bp[4])) 292 ND_PRINT((ndo, " [gaddr %s]", ipaddr_string(ndo, &bp[4]))); 293 if (len != 8) 294 ND_PRINT((ndo, " [len %d]", len)); 295 } 296 break; 297 case 0x12: 298 ND_TCHECK2(bp[4], 4); 299 ND_PRINT((ndo, "igmp v1 report %s", ipaddr_string(ndo, &bp[4]))); 300 if (len != 8) 301 ND_PRINT((ndo, " [len %d]", len)); 302 break; 303 case 0x16: 304 ND_TCHECK2(bp[4], 4); 305 ND_PRINT((ndo, "igmp v2 report %s", ipaddr_string(ndo, &bp[4]))); 306 break; 307 case 0x22: 308 ND_PRINT((ndo, "igmp v3 report")); 309 print_igmpv3_report(ndo, bp, len); 310 break; 311 case 0x17: 312 ND_TCHECK2(bp[4], 4); 313 ND_PRINT((ndo, "igmp leave %s", ipaddr_string(ndo, &bp[4]))); 314 break; 315 case 0x13: 316 ND_PRINT((ndo, "igmp dvmrp")); 317 if (len < 8) 318 ND_PRINT((ndo, " [len %d]", len)); 319 else 320 dvmrp_print(ndo, bp, len); 321 break; 322 case 0x14: 323 ND_PRINT((ndo, "igmp pimv1")); 324 pimv1_print(ndo, bp, len); 325 break; 326 case 0x1e: 327 print_mresp(ndo, bp, len); 328 break; 329 case 0x1f: 330 print_mtrace(ndo, bp, len); 331 break; 332 default: 333 ND_PRINT((ndo, "igmp-%d", bp[0])); 334 break; 335 } 336 337 if (ndo->ndo_vflag && len >= 4 && ND_TTEST2(bp[0], len)) { 338 /* Check the IGMP checksum */ 339 vec[0].ptr = bp; 340 vec[0].len = len; 341 if (in_cksum(vec, 1)) 342 ND_PRINT((ndo, " bad igmp cksum %x!", EXTRACT_16BITS(&bp[2]))); 343 } 344 return; 345trunc: 346 ND_PRINT((ndo, "%s", tstr)); 347} 348