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 * See: RFC 1075 and draft-ietf-idmr-dvmrp-v3 36 * 37 * DVMRP message types and flag values shamelessly stolen from 38 * mrouted/dvmrp.h. 39 */ 40 #define DVMRP_PROBE 1 /* for finding neighbors */ 41 #define DVMRP_REPORT 2 /* for reporting some or all routes */ 42 #define DVMRP_ASK_NEIGHBORS 3 /* sent by mapper, asking for a list */ 43 /* of this router's neighbors */ 44 #define DVMRP_NEIGHBORS 4 /* response to such a request */ 45 #define DVMRP_ASK_NEIGHBORS2 5 /* as above, want new format reply */ 46 #define DVMRP_NEIGHBORS2 6 47 #define DVMRP_PRUNE 7 /* prune message */ 48 #define DVMRP_GRAFT 8 /* graft message */ 49 #define DVMRP_GRAFT_ACK 9 /* graft acknowledgement */ 50 51 /* 52 * 'flags' byte values in DVMRP_NEIGHBORS2 reply. 53 */ 54 #define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */ 55 #define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */ 56 #define DVMRP_NF_DOWN 0x10 /* kernel state of interface */ 57 #define DVMRP_NF_DISABLED 0x20 /* administratively disabled */ 58 #define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */ 59 60 static int print_probe(netdissect_options *, const u_char *, const u_char *, u_int); 61 static int print_report(netdissect_options *, const u_char *, const u_char *, u_int); 62 static int print_neighbors(netdissect_options *, const u_char *, const u_char *, u_int); 63 static int print_neighbors2(netdissect_options *, const u_char *, const u_char *, u_int, uint8_t, uint8_t); 64 static int print_prune(netdissect_options *, const u_char *); 65 static int print_graft(netdissect_options *, const u_char *); 66 static int print_graft_ack(netdissect_options *, const u_char *); 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 uint8_t major_version, minor_version; 75 76 ep = (const u_char *)ndo->ndo_snapend; 77 if (bp >= ep) 78 return; 79 80 ND_TCHECK(bp[1]); 81 type = bp[1]; 82 83 /* Skip IGMP header */ 84 bp += 8; 85 len -= 8; 86 87 switch (type) { 88 89 case DVMRP_PROBE: 90 ND_PRINT((ndo, " Probe")); 91 if (ndo->ndo_vflag) { 92 if (print_probe(ndo, bp, ep, len) < 0) 93 goto trunc; 94 } 95 break; 96 97 case DVMRP_REPORT: 98 ND_PRINT((ndo, " Report")); 99 if (ndo->ndo_vflag > 1) { 100 if (print_report(ndo, bp, ep, len) < 0) 101 goto trunc; 102 } 103 break; 104 105 case DVMRP_ASK_NEIGHBORS: 106 ND_PRINT((ndo, " Ask-neighbors(old)")); 107 break; 108 109 case DVMRP_NEIGHBORS: 110 ND_PRINT((ndo, " Neighbors(old)")); 111 if (print_neighbors(ndo, bp, ep, len) < 0) 112 goto trunc; 113 break; 114 115 case DVMRP_ASK_NEIGHBORS2: 116 ND_PRINT((ndo, " Ask-neighbors2")); 117 break; 118 119 case DVMRP_NEIGHBORS2: 120 ND_PRINT((ndo, " Neighbors2")); 121 /* 122 * extract version from IGMP group address field 123 */ 124 bp -= 4; 125 ND_TCHECK2(bp[0], 4); 126 major_version = *(bp + 3); 127 minor_version = *(bp + 2); 128 bp += 4; 129 if (print_neighbors2(ndo, bp, ep, len, major_version, 130 minor_version) < 0) 131 goto trunc; 132 break; 133 134 case DVMRP_PRUNE: 135 ND_PRINT((ndo, " Prune")); 136 if (print_prune(ndo, bp) < 0) 137 goto trunc; 138 break; 139 140 case DVMRP_GRAFT: 141 ND_PRINT((ndo, " Graft")); 142 if (print_graft(ndo, bp) < 0) 143 goto trunc; 144 break; 145 146 case DVMRP_GRAFT_ACK: 147 ND_PRINT((ndo, " Graft-ACK")); 148 if (print_graft_ack(ndo, bp) < 0) 149 goto trunc; 150 break; 151 152 default: 153 ND_PRINT((ndo, " [type %d]", type)); 154 break; 155 } 156 return; 157 158 trunc: 159 ND_PRINT((ndo, "[|dvmrp]")); 160 return; 161 } 162 163 static int 164 print_report(netdissect_options *ndo, 165 register const u_char *bp, register const u_char *ep, 166 register u_int len) 167 { 168 register uint32_t mask, origin; 169 register int metric, done; 170 register u_int i, width; 171 172 while (len > 0) { 173 if (len < 3) { 174 ND_PRINT((ndo, " [|]")); 175 return (0); 176 } 177 ND_TCHECK2(bp[0], 3); 178 mask = (uint32_t)0xff << 24 | bp[0] << 16 | bp[1] << 8 | bp[2]; 179 width = 1; 180 if (bp[0]) 181 width = 2; 182 if (bp[1]) 183 width = 3; 184 if (bp[2]) 185 width = 4; 186 187 ND_PRINT((ndo, "\n\tMask %s", intoa(htonl(mask)))); 188 bp += 3; 189 len -= 3; 190 do { 191 if (bp + width + 1 > ep) { 192 ND_PRINT((ndo, " [|]")); 193 return (0); 194 } 195 if (len < width + 1) { 196 ND_PRINT((ndo, "\n\t [Truncated Report]")); 197 return (0); 198 } 199 origin = 0; 200 for (i = 0; i < width; ++i) { 201 ND_TCHECK(*bp); 202 origin = origin << 8 | *bp++; 203 } 204 for ( ; i < 4; ++i) 205 origin <<= 8; 206 207 ND_TCHECK(*bp); 208 metric = *bp++; 209 done = metric & 0x80; 210 metric &= 0x7f; 211 ND_PRINT((ndo, "\n\t %s metric %d", intoa(htonl(origin)), 212 metric)); 213 len -= width + 1; 214 } while (!done); 215 } 216 return (0); 217 trunc: 218 return (-1); 219 } 220 221 static int 222 print_probe(netdissect_options *ndo, 223 register const u_char *bp, register const u_char *ep, 224 register u_int len) 225 { 226 register uint32_t genid; 227 228 ND_TCHECK2(bp[0], 4); 229 if ((len < 4) || ((bp + 4) > ep)) { 230 /* { (ctags) */ 231 ND_PRINT((ndo, " [|}")); 232 return (0); 233 } 234 genid = EXTRACT_32BITS(bp); 235 bp += 4; 236 len -= 4; 237 ND_PRINT((ndo, ndo->ndo_vflag > 1 ? "\n\t" : " ")); 238 ND_PRINT((ndo, "genid %u", genid)); 239 if (ndo->ndo_vflag < 2) 240 return (0); 241 242 while ((len > 0) && (bp < ep)) { 243 ND_TCHECK2(bp[0], 4); 244 ND_PRINT((ndo, "\n\tneighbor %s", ipaddr_string(ndo, bp))); 245 bp += 4; len -= 4; 246 } 247 return (0); 248 trunc: 249 return (-1); 250 } 251 252 static int 253 print_neighbors(netdissect_options *ndo, 254 register const u_char *bp, register const u_char *ep, 255 register u_int len) 256 { 257 const u_char *laddr; 258 register u_char metric; 259 register u_char thresh; 260 register int ncount; 261 262 while (len > 0 && bp < ep) { 263 ND_TCHECK2(bp[0], 7); 264 laddr = bp; 265 bp += 4; 266 metric = *bp++; 267 thresh = *bp++; 268 ncount = *bp++; 269 len -= 7; 270 while (--ncount >= 0) { 271 ND_TCHECK2(bp[0], 4); 272 ND_PRINT((ndo, " [%s ->", ipaddr_string(ndo, laddr))); 273 ND_PRINT((ndo, " %s, (%d/%d)]", 274 ipaddr_string(ndo, bp), metric, thresh)); 275 bp += 4; 276 len -= 4; 277 } 278 } 279 return (0); 280 trunc: 281 return (-1); 282 } 283 284 static int 285 print_neighbors2(netdissect_options *ndo, 286 register const u_char *bp, register const u_char *ep, 287 register u_int len, uint8_t major_version, 288 uint8_t minor_version) 289 { 290 const u_char *laddr; 291 register u_char metric, thresh, flags; 292 register int ncount; 293 294 ND_PRINT((ndo, " (v %d.%d):", major_version, minor_version)); 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