1/* 2 * Copyright (c) 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-dvmrp.c,v 1.8 2023/08/17 20:19:40 christos Exp $"); 25#endif 26 27/* \summary: Distance Vector Multicast Routing Protocol 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 "extract.h" 37#include "addrtoname.h" 38 39/* 40 * See: RFC 1075 and draft-ietf-idmr-dvmrp-v3 41 * 42 * DVMRP message types and flag values shamelessly stolen from 43 * mrouted/dvmrp.h. 44 */ 45#define DVMRP_PROBE 1 /* for finding neighbors */ 46#define DVMRP_REPORT 2 /* for reporting some or all routes */ 47#define DVMRP_ASK_NEIGHBORS 3 /* sent by mapper, asking for a list */ 48 /* of this router's neighbors */ 49#define DVMRP_NEIGHBORS 4 /* response to such a request */ 50#define DVMRP_ASK_NEIGHBORS2 5 /* as above, want new format reply */ 51#define DVMRP_NEIGHBORS2 6 52#define DVMRP_PRUNE 7 /* prune message */ 53#define DVMRP_GRAFT 8 /* graft message */ 54#define DVMRP_GRAFT_ACK 9 /* graft acknowledgement */ 55static const struct tok dvmrp_msgtype_str[] = { 56 { DVMRP_PROBE, "Probe" }, 57 { DVMRP_REPORT, "Report" }, 58 { DVMRP_ASK_NEIGHBORS, "Ask-neighbors(old)" }, 59 { DVMRP_NEIGHBORS, "Neighbors(old)" }, 60 { DVMRP_ASK_NEIGHBORS2, "Ask-neighbors2" }, 61 { DVMRP_NEIGHBORS2, "Neighbors2" }, 62 { DVMRP_PRUNE, "Prune" }, 63 { DVMRP_GRAFT, "Graft" }, 64 { DVMRP_GRAFT_ACK, "Graft-ACK" }, 65 { 0, NULL } 66}; 67 68/* 69 * 'flags' byte values in DVMRP_NEIGHBORS2 reply. 70 */ 71#define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */ 72#define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */ 73#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */ 74#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */ 75#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */ 76 77static void print_probe(netdissect_options *, const u_char *, u_int); 78static void print_report(netdissect_options *, const u_char *, u_int); 79static void print_neighbors(netdissect_options *, const u_char *, u_int); 80static void print_neighbors2(netdissect_options *, const u_char *, u_int, uint8_t, uint8_t); 81 82void 83dvmrp_print(netdissect_options *ndo, 84 const u_char *bp, u_int len) 85{ 86 u_char type; 87 uint8_t major_version, minor_version; 88 89 ndo->ndo_protocol = "dvmrp"; 90 if (len < 8) { 91 ND_PRINT(" [length %u < 8]", len); 92 goto invalid; 93 } 94 95 type = GET_U_1(bp + 1); 96 97 /* Skip IGMP header */ 98 bp += 8; 99 len -= 8; 100 101 ND_PRINT(" %s", tok2str(dvmrp_msgtype_str, "[type %u]", type)); 102 switch (type) { 103 104 case DVMRP_PROBE: 105 if (ndo->ndo_vflag) { 106 print_probe(ndo, bp, len); 107 } 108 break; 109 110 case DVMRP_REPORT: 111 if (ndo->ndo_vflag > 1) { 112 print_report(ndo, bp, len); 113 } 114 break; 115 116 case DVMRP_NEIGHBORS: 117 print_neighbors(ndo, bp, len); 118 break; 119 120 case DVMRP_NEIGHBORS2: 121 /* 122 * extract version from IGMP group address field 123 */ 124 bp -= 4; 125 major_version = GET_U_1(bp + 3); 126 minor_version = GET_U_1(bp + 2); 127 bp += 4; 128 print_neighbors2(ndo, bp, len, major_version, minor_version); 129 break; 130 131 case DVMRP_PRUNE: 132 ND_PRINT(" src %s grp %s", GET_IPADDR_STRING(bp), GET_IPADDR_STRING(bp + 4)); 133 ND_PRINT(" timer "); 134 unsigned_relts_print(ndo, GET_BE_U_4(bp + 8)); 135 break; 136 137 case DVMRP_GRAFT: 138 ND_PRINT(" src %s grp %s", GET_IPADDR_STRING(bp), GET_IPADDR_STRING(bp + 4)); 139 break; 140 141 case DVMRP_GRAFT_ACK: 142 ND_PRINT(" src %s grp %s", GET_IPADDR_STRING(bp), GET_IPADDR_STRING(bp + 4)); 143 break; 144 } 145 return; 146 147invalid: 148 nd_print_invalid(ndo); 149} 150 151static void 152print_report(netdissect_options *ndo, 153 const u_char *bp, 154 u_int len) 155{ 156 uint32_t mask, origin; 157 u_int metric, done; 158 u_int i, width; 159 160 while (len > 0) { 161 if (len < 3) { 162 ND_PRINT(" [length %u < 3]", len); 163 goto invalid; 164 } 165 mask = (uint32_t)0xff << 24 | GET_U_1(bp) << 16 | 166 GET_U_1(bp + 1) << 8 | GET_U_1(bp + 2); 167 width = 1; 168 if (GET_U_1(bp)) 169 width = 2; 170 if (GET_U_1(bp + 1)) 171 width = 3; 172 if (GET_U_1(bp + 2)) 173 width = 4; 174 175 ND_PRINT("\n\tMask %s", intoa(htonl(mask))); 176 bp += 3; 177 len -= 3; 178 do { 179 if (len < width + 1) { 180 ND_PRINT("\n\t [Truncated Report]"); 181 goto invalid; 182 } 183 origin = 0; 184 for (i = 0; i < width; ++i) { 185 origin = origin << 8 | GET_U_1(bp); 186 bp++; 187 } 188 for ( ; i < 4; ++i) 189 origin <<= 8; 190 191 metric = GET_U_1(bp); 192 bp++; 193 done = metric & 0x80; 194 metric &= 0x7f; 195 ND_PRINT("\n\t %s metric %u", intoa(htonl(origin)), 196 metric); 197 len -= width + 1; 198 } while (!done); 199 } 200 return; 201 202invalid: 203 nd_print_invalid(ndo); 204} 205 206static void 207print_probe(netdissect_options *ndo, 208 const u_char *bp, 209 u_int len) 210{ 211 if (len < 4) { 212 ND_PRINT(" [full length %u < 4]", len); 213 goto invalid; 214 } 215 ND_PRINT(ndo->ndo_vflag > 1 ? "\n\t" : " "); 216 ND_PRINT("genid %u", GET_BE_U_4(bp)); 217 if (ndo->ndo_vflag < 2) 218 return; 219 220 bp += 4; 221 len -= 4; 222 while (len > 0) { 223 if (len < 4) { 224 ND_PRINT("[remaining length %u < 4]", len); 225 goto invalid; 226 } 227 ND_PRINT("\n\tneighbor %s", GET_IPADDR_STRING(bp)); 228 bp += 4; len -= 4; 229 } 230 return; 231 232invalid: 233 nd_print_invalid(ndo); 234} 235 236static void 237print_neighbors(netdissect_options *ndo, 238 const u_char *bp, 239 u_int len) 240{ 241 const u_char *laddr; 242 u_char metric; 243 u_char thresh; 244 int ncount; 245 246 while (len > 0) { 247 if (len < 7) { 248 ND_PRINT(" [length %u < 7]", len); 249 goto invalid; 250 } 251 laddr = bp; 252 bp += 4; 253 metric = GET_U_1(bp); 254 bp++; 255 thresh = GET_U_1(bp); 256 bp++; 257 ncount = GET_U_1(bp); 258 bp++; 259 len -= 7; 260 while (--ncount >= 0) { 261 if (len < 4) { 262 ND_PRINT(" [length %u < 4]", len); 263 goto invalid; 264 } 265 ND_PRINT(" [%s ->", GET_IPADDR_STRING(laddr)); 266 ND_PRINT(" %s, (%u/%u)]", 267 GET_IPADDR_STRING(bp), metric, thresh); 268 bp += 4; 269 len -= 4; 270 } 271 } 272 return; 273 274invalid: 275 nd_print_invalid(ndo); 276} 277 278static void 279print_neighbors2(netdissect_options *ndo, 280 const u_char *bp, 281 u_int len, uint8_t major_version, 282 uint8_t minor_version) 283{ 284 const u_char *laddr; 285 u_char metric, thresh, flags; 286 int ncount; 287 288 ND_PRINT(" (v %u.%u):", major_version, minor_version); 289 290 while (len > 0) { 291 if (len < 8) { 292 ND_PRINT(" [length %u < 8]", len); 293 goto invalid; 294 } 295 laddr = bp; 296 bp += 4; 297 metric = GET_U_1(bp); 298 bp++; 299 thresh = GET_U_1(bp); 300 bp++; 301 flags = GET_U_1(bp); 302 bp++; 303 ncount = GET_U_1(bp); 304 bp++; 305 len -= 8; 306 while (--ncount >= 0 && len > 0) { 307 if (len < 4) { 308 ND_PRINT(" [length %u < 4]", len); 309 goto invalid; 310 } 311 ND_PRINT(" [%s -> ", GET_IPADDR_STRING(laddr)); 312 ND_PRINT("%s (%u/%u", GET_IPADDR_STRING(bp), 313 metric, thresh); 314 if (flags & DVMRP_NF_TUNNEL) 315 ND_PRINT("/tunnel"); 316 if (flags & DVMRP_NF_SRCRT) 317 ND_PRINT("/srcrt"); 318 if (flags & DVMRP_NF_QUERIER) 319 ND_PRINT("/querier"); 320 if (flags & DVMRP_NF_DISABLED) 321 ND_PRINT("/disabled"); 322 if (flags & DVMRP_NF_DOWN) 323 ND_PRINT("/down"); 324 ND_PRINT(")]"); 325 bp += 4; 326 len -= 4; 327 } 328 if (ncount != -1) { 329 ND_PRINT(" [invalid ncount]"); 330 goto invalid; 331 } 332 } 333 return; 334 335invalid: 336 nd_print_invalid(ndo); 337} 338