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