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