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