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.7 2019/10/01 16:06:16 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 */ 55 56 /* 57 * 'flags' byte values in DVMRP_NEIGHBORS2 reply. 58 */ 59 #define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */ 60 #define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */ 61 #define DVMRP_NF_DOWN 0x10 /* kernel state of interface */ 62 #define DVMRP_NF_DISABLED 0x20 /* administratively disabled */ 63 #define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */ 64 65 static int print_probe(netdissect_options *, const u_char *, const u_char *, u_int); 66 static int print_report(netdissect_options *, const u_char *, const u_char *, u_int); 67 static int print_neighbors(netdissect_options *, const u_char *, const u_char *, u_int); 68 static int print_neighbors2(netdissect_options *, const u_char *, const u_char *, u_int, uint8_t, uint8_t); 69 static int print_prune(netdissect_options *, const u_char *); 70 static int print_graft(netdissect_options *, const u_char *); 71 static int print_graft_ack(netdissect_options *, const u_char *); 72 73 void 74 dvmrp_print(netdissect_options *ndo, 75 register const u_char *bp, register u_int len) 76 { 77 register const u_char *ep; 78 register u_char type; 79 uint8_t major_version, minor_version; 80 81 ep = (const u_char *)ndo->ndo_snapend; 82 if (bp >= ep) 83 return; 84 85 ND_TCHECK(bp[1]); 86 type = bp[1]; 87 88 /* Skip IGMP header */ 89 bp += 8; 90 len -= 8; 91 92 switch (type) { 93 94 case DVMRP_PROBE: 95 ND_PRINT((ndo, " Probe")); 96 if (ndo->ndo_vflag) { 97 if (print_probe(ndo, bp, ep, len) < 0) 98 goto trunc; 99 } 100 break; 101 102 case DVMRP_REPORT: 103 ND_PRINT((ndo, " Report")); 104 if (ndo->ndo_vflag > 1) { 105 if (print_report(ndo, bp, ep, len) < 0) 106 goto trunc; 107 } 108 break; 109 110 case DVMRP_ASK_NEIGHBORS: 111 ND_PRINT((ndo, " Ask-neighbors(old)")); 112 break; 113 114 case DVMRP_NEIGHBORS: 115 ND_PRINT((ndo, " Neighbors(old)")); 116 if (print_neighbors(ndo, bp, ep, len) < 0) 117 goto trunc; 118 break; 119 120 case DVMRP_ASK_NEIGHBORS2: 121 ND_PRINT((ndo, " Ask-neighbors2")); 122 break; 123 124 case DVMRP_NEIGHBORS2: 125 ND_PRINT((ndo, " Neighbors2")); 126 /* 127 * extract version from IGMP group address field 128 */ 129 bp -= 4; 130 ND_TCHECK2(bp[0], 4); 131 major_version = *(bp + 3); 132 minor_version = *(bp + 2); 133 bp += 4; 134 if (print_neighbors2(ndo, bp, ep, len, major_version, 135 minor_version) < 0) 136 goto trunc; 137 break; 138 139 case DVMRP_PRUNE: 140 ND_PRINT((ndo, " Prune")); 141 if (print_prune(ndo, bp) < 0) 142 goto trunc; 143 break; 144 145 case DVMRP_GRAFT: 146 ND_PRINT((ndo, " Graft")); 147 if (print_graft(ndo, bp) < 0) 148 goto trunc; 149 break; 150 151 case DVMRP_GRAFT_ACK: 152 ND_PRINT((ndo, " Graft-ACK")); 153 if (print_graft_ack(ndo, bp) < 0) 154 goto trunc; 155 break; 156 157 default: 158 ND_PRINT((ndo, " [type %d]", type)); 159 break; 160 } 161 return; 162 163 trunc: 164 ND_PRINT((ndo, "[|dvmrp]")); 165 return; 166 } 167 168 static int 169 print_report(netdissect_options *ndo, 170 register const u_char *bp, register const u_char *ep, 171 register u_int len) 172 { 173 register uint32_t mask, origin; 174 register int metric, done; 175 register u_int i, width; 176 177 while (len > 0) { 178 if (len < 3) { 179 ND_PRINT((ndo, " [|]")); 180 return (0); 181 } 182 ND_TCHECK2(bp[0], 3); 183 mask = (uint32_t)0xff << 24 | bp[0] << 16 | bp[1] << 8 | bp[2]; 184 width = 1; 185 if (bp[0]) 186 width = 2; 187 if (bp[1]) 188 width = 3; 189 if (bp[2]) 190 width = 4; 191 192 ND_PRINT((ndo, "\n\tMask %s", intoa(htonl(mask)))); 193 bp += 3; 194 len -= 3; 195 do { 196 if (bp + width + 1 > ep) { 197 ND_PRINT((ndo, " [|]")); 198 return (0); 199 } 200 if (len < width + 1) { 201 ND_PRINT((ndo, "\n\t [Truncated Report]")); 202 return (0); 203 } 204 origin = 0; 205 for (i = 0; i < width; ++i) { 206 ND_TCHECK(*bp); 207 origin = origin << 8 | *bp++; 208 } 209 for ( ; i < 4; ++i) 210 origin <<= 8; 211 212 ND_TCHECK(*bp); 213 metric = *bp++; 214 done = metric & 0x80; 215 metric &= 0x7f; 216 ND_PRINT((ndo, "\n\t %s metric %d", intoa(htonl(origin)), 217 metric)); 218 len -= width + 1; 219 } while (!done); 220 } 221 return (0); 222 trunc: 223 return (-1); 224 } 225 226 static int 227 print_probe(netdissect_options *ndo, 228 register const u_char *bp, register const u_char *ep, 229 register u_int len) 230 { 231 register uint32_t genid; 232 233 ND_TCHECK2(bp[0], 4); 234 if ((len < 4) || ((bp + 4) > ep)) { 235 /* { (ctags) */ 236 ND_PRINT((ndo, " [|}")); 237 return (0); 238 } 239 genid = EXTRACT_32BITS(bp); 240 bp += 4; 241 len -= 4; 242 ND_PRINT((ndo, ndo->ndo_vflag > 1 ? "\n\t" : " ")); 243 ND_PRINT((ndo, "genid %u", genid)); 244 if (ndo->ndo_vflag < 2) 245 return (0); 246 247 while ((len > 0) && (bp < ep)) { 248 ND_TCHECK2(bp[0], 4); 249 ND_PRINT((ndo, "\n\tneighbor %s", ipaddr_string(ndo, bp))); 250 bp += 4; len -= 4; 251 } 252 return (0); 253 trunc: 254 return (-1); 255 } 256 257 static int 258 print_neighbors(netdissect_options *ndo, 259 register const u_char *bp, register const u_char *ep, 260 register u_int len) 261 { 262 const u_char *laddr; 263 register u_char metric; 264 register u_char thresh; 265 register int ncount; 266 267 while (len > 0 && bp < ep) { 268 ND_TCHECK2(bp[0], 7); 269 laddr = bp; 270 bp += 4; 271 metric = *bp++; 272 thresh = *bp++; 273 ncount = *bp++; 274 len -= 7; 275 while (--ncount >= 0) { 276 ND_TCHECK2(bp[0], 4); 277 ND_PRINT((ndo, " [%s ->", ipaddr_string(ndo, laddr))); 278 ND_PRINT((ndo, " %s, (%d/%d)]", 279 ipaddr_string(ndo, bp), metric, thresh)); 280 bp += 4; 281 len -= 4; 282 } 283 } 284 return (0); 285 trunc: 286 return (-1); 287 } 288 289 static int 290 print_neighbors2(netdissect_options *ndo, 291 register const u_char *bp, register const u_char *ep, 292 register u_int len, uint8_t major_version, 293 uint8_t minor_version) 294 { 295 const u_char *laddr; 296 register u_char metric, thresh, flags; 297 register int ncount; 298 299 ND_PRINT((ndo, " (v %d.%d):", major_version, minor_version)); 300 301 while (len > 0 && bp < ep) { 302 ND_TCHECK2(bp[0], 8); 303 laddr = bp; 304 bp += 4; 305 metric = *bp++; 306 thresh = *bp++; 307 flags = *bp++; 308 ncount = *bp++; 309 len -= 8; 310 while (--ncount >= 0 && (len >= 4) && (bp + 4) <= ep) { 311 ND_PRINT((ndo, " [%s -> ", ipaddr_string(ndo, laddr))); 312 ND_PRINT((ndo, "%s (%d/%d", ipaddr_string(ndo, bp), 313 metric, thresh)); 314 if (flags & DVMRP_NF_TUNNEL) 315 ND_PRINT((ndo, "/tunnel")); 316 if (flags & DVMRP_NF_SRCRT) 317 ND_PRINT((ndo, "/srcrt")); 318 if (flags & DVMRP_NF_QUERIER) 319 ND_PRINT((ndo, "/querier")); 320 if (flags & DVMRP_NF_DISABLED) 321 ND_PRINT((ndo, "/disabled")); 322 if (flags & DVMRP_NF_DOWN) 323 ND_PRINT((ndo, "/down")); 324 ND_PRINT((ndo, ")]")); 325 bp += 4; 326 len -= 4; 327 } 328 if (ncount != -1) { 329 ND_PRINT((ndo, " [|]")); 330 return (0); 331 } 332 } 333 return (0); 334 trunc: 335 return (-1); 336 } 337 338 static int 339 print_prune(netdissect_options *ndo, 340 register const u_char *bp) 341 { 342 ND_TCHECK2(bp[0], 12); 343 ND_PRINT((ndo, " src %s grp %s", ipaddr_string(ndo, bp), ipaddr_string(ndo, bp + 4))); 344 bp += 8; 345 ND_PRINT((ndo, " timer ")); 346 unsigned_relts_print(ndo, EXTRACT_32BITS(bp)); 347 return (0); 348 trunc: 349 return (-1); 350 } 351 352 static int 353 print_graft(netdissect_options *ndo, 354 register const u_char *bp) 355 { 356 ND_TCHECK2(bp[0], 8); 357 ND_PRINT((ndo, " src %s grp %s", ipaddr_string(ndo, bp), ipaddr_string(ndo, bp + 4))); 358 return (0); 359 trunc: 360 return (-1); 361 } 362 363 static int 364 print_graft_ack(netdissect_options *ndo, 365 register const u_char *bp) 366 { 367 ND_TCHECK2(bp[0], 8); 368 ND_PRINT((ndo, " src %s grp %s", ipaddr_string(ndo, bp), ipaddr_string(ndo, bp + 4))); 369 return (0); 370 trunc: 371 return (-1); 372 } 373