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