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