Home | History | Annotate | Download | only in tcpdump
      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