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 static const struct tok dvmrp_msgtype_str[] = { 51 { DVMRP_PROBE, "Probe" }, 52 { DVMRP_REPORT, "Report" }, 53 { DVMRP_ASK_NEIGHBORS, "Ask-neighbors(old)" }, 54 { DVMRP_NEIGHBORS, "Neighbors(old)" }, 55 { DVMRP_ASK_NEIGHBORS2, "Ask-neighbors2" }, 56 { DVMRP_NEIGHBORS2, "Neighbors2" }, 57 { DVMRP_PRUNE, "Prune" }, 58 { DVMRP_GRAFT, "Graft" }, 59 { DVMRP_GRAFT_ACK, "Graft-ACK" }, 60 { 0, NULL } 61 }; 62 63 /* 64 * 'flags' byte values in DVMRP_NEIGHBORS2 reply. 65 */ 66 #define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */ 67 #define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */ 68 #define DVMRP_NF_DOWN 0x10 /* kernel state of interface */ 69 #define DVMRP_NF_DISABLED 0x20 /* administratively disabled */ 70 #define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */ 71 72 static void print_probe(netdissect_options *, const u_char *, u_int); 73 static void print_report(netdissect_options *, const u_char *, u_int); 74 static void print_neighbors(netdissect_options *, const u_char *, u_int); 75 static void print_neighbors2(netdissect_options *, const u_char *, u_int, uint8_t, uint8_t); 76 77 void 78 dvmrp_print(netdissect_options *ndo, 79 const u_char *bp, u_int len) 80 { 81 u_char type; 82 uint8_t major_version, minor_version; 83 84 ndo->ndo_protocol = "dvmrp"; 85 if (len < 8) { 86 ND_PRINT(" [length %u < 8]", len); 87 goto invalid; 88 } 89 90 type = GET_U_1(bp + 1); 91 92 /* Skip IGMP header */ 93 bp += 8; 94 len -= 8; 95 96 ND_PRINT(" %s", tok2str(dvmrp_msgtype_str, "[type %u]", type)); 97 switch (type) { 98 99 case DVMRP_PROBE: 100 if (ndo->ndo_vflag) { 101 print_probe(ndo, bp, len); 102 } 103 break; 104 105 case DVMRP_REPORT: 106 if (ndo->ndo_vflag > 1) { 107 print_report(ndo, bp, len); 108 } 109 break; 110 111 case DVMRP_NEIGHBORS: 112 print_neighbors(ndo, bp, len); 113 break; 114 115 case DVMRP_NEIGHBORS2: 116 /* 117 * extract version from IGMP group address field 118 */ 119 bp -= 4; 120 major_version = GET_U_1(bp + 3); 121 minor_version = GET_U_1(bp + 2); 122 bp += 4; 123 print_neighbors2(ndo, bp, len, major_version, minor_version); 124 break; 125 126 case DVMRP_PRUNE: 127 ND_PRINT(" src %s grp %s", GET_IPADDR_STRING(bp), GET_IPADDR_STRING(bp + 4)); 128 ND_PRINT(" timer "); 129 unsigned_relts_print(ndo, GET_BE_U_4(bp + 8)); 130 break; 131 132 case DVMRP_GRAFT: 133 ND_PRINT(" src %s grp %s", GET_IPADDR_STRING(bp), GET_IPADDR_STRING(bp + 4)); 134 break; 135 136 case DVMRP_GRAFT_ACK: 137 ND_PRINT(" src %s grp %s", GET_IPADDR_STRING(bp), GET_IPADDR_STRING(bp + 4)); 138 break; 139 } 140 return; 141 142 invalid: 143 nd_print_invalid(ndo); 144 } 145 146 static void 147 print_report(netdissect_options *ndo, 148 const u_char *bp, 149 u_int len) 150 { 151 uint32_t mask, origin; 152 u_int metric, done; 153 u_int i, width; 154 155 while (len > 0) { 156 if (len < 3) { 157 ND_PRINT(" [length %u < 3]", len); 158 goto invalid; 159 } 160 mask = (uint32_t)0xff << 24 | GET_U_1(bp) << 16 | 161 GET_U_1(bp + 1) << 8 | GET_U_1(bp + 2); 162 width = 1; 163 if (GET_U_1(bp)) 164 width = 2; 165 if (GET_U_1(bp + 1)) 166 width = 3; 167 if (GET_U_1(bp + 2)) 168 width = 4; 169 170 ND_PRINT("\n\tMask %s", intoa(htonl(mask))); 171 bp += 3; 172 len -= 3; 173 do { 174 if (len < width + 1) { 175 ND_PRINT("\n\t [Truncated Report]"); 176 goto invalid; 177 } 178 origin = 0; 179 for (i = 0; i < width; ++i) { 180 origin = origin << 8 | GET_U_1(bp); 181 bp++; 182 } 183 for ( ; i < 4; ++i) 184 origin <<= 8; 185 186 metric = GET_U_1(bp); 187 bp++; 188 done = metric & 0x80; 189 metric &= 0x7f; 190 ND_PRINT("\n\t %s metric %u", intoa(htonl(origin)), 191 metric); 192 len -= width + 1; 193 } while (!done); 194 } 195 return; 196 197 invalid: 198 nd_print_invalid(ndo); 199 } 200 201 static void 202 print_probe(netdissect_options *ndo, 203 const u_char *bp, 204 u_int len) 205 { 206 if (len < 4) { 207 ND_PRINT(" [full length %u < 4]", len); 208 goto invalid; 209 } 210 ND_PRINT(ndo->ndo_vflag > 1 ? "\n\t" : " "); 211 ND_PRINT("genid %u", GET_BE_U_4(bp)); 212 if (ndo->ndo_vflag < 2) 213 return; 214 215 bp += 4; 216 len -= 4; 217 while (len > 0) { 218 if (len < 4) { 219 ND_PRINT("[remaining length %u < 4]", len); 220 goto invalid; 221 } 222 ND_PRINT("\n\tneighbor %s", GET_IPADDR_STRING(bp)); 223 bp += 4; len -= 4; 224 } 225 return; 226 227 invalid: 228 nd_print_invalid(ndo); 229 } 230 231 static void 232 print_neighbors(netdissect_options *ndo, 233 const u_char *bp, 234 u_int len) 235 { 236 const u_char *laddr; 237 u_char metric; 238 u_char thresh; 239 int ncount; 240 241 while (len > 0) { 242 if (len < 7) { 243 ND_PRINT(" [length %u < 7]", len); 244 goto invalid; 245 } 246 laddr = bp; 247 bp += 4; 248 metric = GET_U_1(bp); 249 bp++; 250 thresh = GET_U_1(bp); 251 bp++; 252 ncount = GET_U_1(bp); 253 bp++; 254 len -= 7; 255 while (--ncount >= 0) { 256 if (len < 4) { 257 ND_PRINT(" [length %u < 4]", len); 258 goto invalid; 259 } 260 ND_PRINT(" [%s ->", GET_IPADDR_STRING(laddr)); 261 ND_PRINT(" %s, (%u/%u)]", 262 GET_IPADDR_STRING(bp), metric, thresh); 263 bp += 4; 264 len -= 4; 265 } 266 } 267 return; 268 269 invalid: 270 nd_print_invalid(ndo); 271 } 272 273 static void 274 print_neighbors2(netdissect_options *ndo, 275 const u_char *bp, 276 u_int len, uint8_t major_version, 277 uint8_t minor_version) 278 { 279 const u_char *laddr; 280 u_char metric, thresh, flags; 281 int ncount; 282 283 ND_PRINT(" (v %u.%u):", major_version, minor_version); 284 285 while (len > 0) { 286 if (len < 8) { 287 ND_PRINT(" [length %u < 8]", len); 288 goto invalid; 289 } 290 laddr = bp; 291 bp += 4; 292 metric = GET_U_1(bp); 293 bp++; 294 thresh = GET_U_1(bp); 295 bp++; 296 flags = GET_U_1(bp); 297 bp++; 298 ncount = GET_U_1(bp); 299 bp++; 300 len -= 8; 301 while (--ncount >= 0 && len > 0) { 302 if (len < 4) { 303 ND_PRINT(" [length %u < 4]", len); 304 goto invalid; 305 } 306 ND_PRINT(" [%s -> ", GET_IPADDR_STRING(laddr)); 307 ND_PRINT("%s (%u/%u", GET_IPADDR_STRING(bp), 308 metric, thresh); 309 if (flags & DVMRP_NF_TUNNEL) 310 ND_PRINT("/tunnel"); 311 if (flags & DVMRP_NF_SRCRT) 312 ND_PRINT("/srcrt"); 313 if (flags & DVMRP_NF_QUERIER) 314 ND_PRINT("/querier"); 315 if (flags & DVMRP_NF_DISABLED) 316 ND_PRINT("/disabled"); 317 if (flags & DVMRP_NF_DOWN) 318 ND_PRINT("/down"); 319 ND_PRINT(")]"); 320 bp += 4; 321 len -= 4; 322 } 323 if (ncount != -1) { 324 ND_PRINT(" [invalid ncount]"); 325 goto invalid; 326 } 327 } 328 return; 329 330 invalid: 331 nd_print_invalid(ndo); 332 } 333