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