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 #define NETDISSECT_REWORKED
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <tcpdump-stdinc.h>
28 
29 #include "interface.h"
30 #include "extract.h"
31 #include "addrtoname.h"
32 
33 /*
34  * DVMRP message types and flag values shamelessly stolen from
35  * mrouted/dvmrp.h.
36  */
37 #define DVMRP_PROBE		1	/* for finding neighbors */
38 #define DVMRP_REPORT		2	/* for reporting some or all routes */
39 #define DVMRP_ASK_NEIGHBORS	3	/* sent by mapper, asking for a list */
40 					/* of this router's neighbors */
41 #define DVMRP_NEIGHBORS		4	/* response to such a request */
42 #define DVMRP_ASK_NEIGHBORS2	5	/* as above, want new format reply */
43 #define DVMRP_NEIGHBORS2	6
44 #define DVMRP_PRUNE		7	/* prune message */
45 #define DVMRP_GRAFT		8	/* graft message */
46 #define DVMRP_GRAFT_ACK		9	/* graft acknowledgement */
47 
48 /*
49  * 'flags' byte values in DVMRP_NEIGHBORS2 reply.
50  */
51 #define DVMRP_NF_TUNNEL		0x01	/* neighbors reached via tunnel */
52 #define DVMRP_NF_SRCRT		0x02	/* tunnel uses IP source routing */
53 #define DVMRP_NF_DOWN		0x10	/* kernel state of interface */
54 #define DVMRP_NF_DISABLED	0x20	/* administratively disabled */
55 #define DVMRP_NF_QUERIER	0x40	/* I am the subnet's querier */
56 
57 static int print_probe(netdissect_options *, const u_char *, const u_char *, u_int);
58 static int print_report(netdissect_options *, const u_char *, const u_char *, u_int);
59 static int print_neighbors(netdissect_options *, const u_char *, const u_char *, u_int);
60 static int print_neighbors2(netdissect_options *, const u_char *, const u_char *, u_int);
61 static int print_prune(netdissect_options *, const u_char *);
62 static int print_graft(netdissect_options *, const u_char *);
63 static int print_graft_ack(netdissect_options *, const u_char *);
64 
65 static uint32_t target_level;
66 
67 void
dvmrp_print(netdissect_options * ndo,register const u_char * bp,register u_int len)68 dvmrp_print(netdissect_options *ndo,
69             register const u_char *bp, register u_int len)
70 {
71 	register const u_char *ep;
72 	register u_char type;
73 
74 	ep = (const u_char *)ndo->ndo_snapend;
75 	if (bp >= ep)
76 		return;
77 
78 	ND_TCHECK(bp[1]);
79 	type = bp[1];
80 
81 	/* Skip IGMP header */
82 	bp += 8;
83 	len -= 8;
84 
85 	switch (type) {
86 
87 	case DVMRP_PROBE:
88 		ND_PRINT((ndo, " Probe"));
89 		if (ndo->ndo_vflag) {
90 			if (print_probe(ndo, bp, ep, len) < 0)
91 				goto trunc;
92 		}
93 		break;
94 
95 	case DVMRP_REPORT:
96 		ND_PRINT((ndo, " Report"));
97 		if (ndo->ndo_vflag > 1) {
98 			if (print_report(ndo, bp, ep, len) < 0)
99 				goto trunc;
100 		}
101 		break;
102 
103 	case DVMRP_ASK_NEIGHBORS:
104 		ND_PRINT((ndo, " Ask-neighbors(old)"));
105 		break;
106 
107 	case DVMRP_NEIGHBORS:
108 		ND_PRINT((ndo, " Neighbors(old)"));
109 		if (print_neighbors(ndo, bp, ep, len) < 0)
110 			goto trunc;
111 		break;
112 
113 	case DVMRP_ASK_NEIGHBORS2:
114 		ND_PRINT((ndo, " Ask-neighbors2"));
115 		break;
116 
117 	case DVMRP_NEIGHBORS2:
118 		ND_PRINT((ndo, " Neighbors2"));
119 		/*
120 		 * extract version and capabilities from IGMP group
121 		 * address field
122 		 */
123 		bp -= 4;
124 		ND_TCHECK2(bp[0], 4);
125 		target_level = (bp[0] << 24) | (bp[1] << 16) |
126 		    (bp[2] << 8) | bp[3];
127 		bp += 4;
128 		if (print_neighbors2(ndo, bp, ep, len) < 0)
129 			goto trunc;
130 		break;
131 
132 	case DVMRP_PRUNE:
133 		ND_PRINT((ndo, " Prune"));
134 		if (print_prune(ndo, bp) < 0)
135 			goto trunc;
136 		break;
137 
138 	case DVMRP_GRAFT:
139 		ND_PRINT((ndo, " Graft"));
140 		if (print_graft(ndo, bp) < 0)
141 			goto trunc;
142 		break;
143 
144 	case DVMRP_GRAFT_ACK:
145 		ND_PRINT((ndo, " Graft-ACK"));
146 		if (print_graft_ack(ndo, bp) < 0)
147 			goto trunc;
148 		break;
149 
150 	default:
151 		ND_PRINT((ndo, " [type %d]", type));
152 		break;
153 	}
154 	return;
155 
156 trunc:
157 	ND_PRINT((ndo, "[|dvmrp]"));
158 	return;
159 }
160 
161 static int
print_report(netdissect_options * ndo,register const u_char * bp,register const u_char * ep,register u_int len)162 print_report(netdissect_options *ndo,
163              register const u_char *bp, register const u_char *ep,
164              register u_int len)
165 {
166 	register uint32_t mask, origin;
167 	register int metric, done;
168 	register u_int i, width;
169 
170 	while (len > 0) {
171 		if (len < 3) {
172 			ND_PRINT((ndo, " [|]"));
173 			return (0);
174 		}
175 		ND_TCHECK2(bp[0], 3);
176 		mask = (uint32_t)0xff << 24 | bp[0] << 16 | bp[1] << 8 | bp[2];
177 		width = 1;
178 		if (bp[0])
179 			width = 2;
180 		if (bp[1])
181 			width = 3;
182 		if (bp[2])
183 			width = 4;
184 
185 		ND_PRINT((ndo, "\n\tMask %s", intoa(htonl(mask))));
186 		bp += 3;
187 		len -= 3;
188 		do {
189 			if (bp + width + 1 > ep) {
190 				ND_PRINT((ndo, " [|]"));
191 				return (0);
192 			}
193 			if (len < width + 1) {
194 				ND_PRINT((ndo, "\n\t  [Truncated Report]"));
195 				return (0);
196 			}
197 			origin = 0;
198 			for (i = 0; i < width; ++i) {
199 				ND_TCHECK(*bp);
200 				origin = origin << 8 | *bp++;
201 			}
202 			for ( ; i < 4; ++i)
203 				origin <<= 8;
204 
205 			ND_TCHECK(*bp);
206 			metric = *bp++;
207 			done = metric & 0x80;
208 			metric &= 0x7f;
209 			ND_PRINT((ndo, "\n\t  %s metric %d", intoa(htonl(origin)),
210 				metric));
211 			len -= width + 1;
212 		} while (!done);
213 	}
214 	return (0);
215 trunc:
216 	return (-1);
217 }
218 
219 static int
print_probe(netdissect_options * ndo,register const u_char * bp,register const u_char * ep,register u_int len)220 print_probe(netdissect_options *ndo,
221             register const u_char *bp, register const u_char *ep,
222             register u_int len)
223 {
224 	register uint32_t genid;
225 
226 	ND_TCHECK2(bp[0], 4);
227 	if ((len < 4) || ((bp + 4) > ep)) {
228 		/* { (ctags) */
229 		ND_PRINT((ndo, " [|}"));
230 		return (0);
231 	}
232 	genid = (bp[0] << 24) | (bp[1] << 16) | (bp[2] << 8) | bp[3];
233 	bp += 4;
234 	len -= 4;
235 	ND_PRINT((ndo, ndo->ndo_vflag > 1 ? "\n\t" : " "));
236 	ND_PRINT((ndo, "genid %u", genid));
237 	if (ndo->ndo_vflag < 2)
238 		return (0);
239 
240 	while ((len > 0) && (bp < ep)) {
241 		ND_TCHECK2(bp[0], 4);
242 		ND_PRINT((ndo, "\n\tneighbor %s", ipaddr_string(ndo, bp)));
243 		bp += 4; len -= 4;
244 	}
245 	return (0);
246 trunc:
247 	return (-1);
248 }
249 
250 static int
print_neighbors(netdissect_options * ndo,register const u_char * bp,register const u_char * ep,register u_int len)251 print_neighbors(netdissect_options *ndo,
252                 register const u_char *bp, register const u_char *ep,
253                 register u_int len)
254 {
255 	const u_char *laddr;
256 	register u_char metric;
257 	register u_char thresh;
258 	register int ncount;
259 
260 	while (len > 0 && bp < ep) {
261 		ND_TCHECK2(bp[0], 7);
262 		laddr = bp;
263 		bp += 4;
264 		metric = *bp++;
265 		thresh = *bp++;
266 		ncount = *bp++;
267 		len -= 7;
268 		while (--ncount >= 0) {
269 			ND_TCHECK2(bp[0], 4);
270 			ND_PRINT((ndo, " [%s ->", ipaddr_string(ndo, laddr)));
271 			ND_PRINT((ndo, " %s, (%d/%d)]",
272 				   ipaddr_string(ndo, bp), metric, thresh));
273 			bp += 4;
274 			len -= 4;
275 		}
276 	}
277 	return (0);
278 trunc:
279 	return (-1);
280 }
281 
282 static int
print_neighbors2(netdissect_options * ndo,register const u_char * bp,register const u_char * ep,register u_int len)283 print_neighbors2(netdissect_options *ndo,
284                  register const u_char *bp, register const u_char *ep,
285                  register u_int len)
286 {
287 	const u_char *laddr;
288 	register u_char metric, thresh, flags;
289 	register int ncount;
290 
291 	ND_PRINT((ndo, " (v %d.%d):",
292 	       (int)target_level & 0xff,
293 	       (int)(target_level >> 8) & 0xff));
294 
295 	while (len > 0 && bp < ep) {
296 		ND_TCHECK2(bp[0], 8);
297 		laddr = bp;
298 		bp += 4;
299 		metric = *bp++;
300 		thresh = *bp++;
301 		flags = *bp++;
302 		ncount = *bp++;
303 		len -= 8;
304 		while (--ncount >= 0 && (len >= 4) && (bp + 4) <= ep) {
305 			ND_PRINT((ndo, " [%s -> ", ipaddr_string(ndo, laddr)));
306 			ND_PRINT((ndo, "%s (%d/%d", ipaddr_string(ndo, bp),
307 				     metric, thresh));
308 			if (flags & DVMRP_NF_TUNNEL)
309 				ND_PRINT((ndo, "/tunnel"));
310 			if (flags & DVMRP_NF_SRCRT)
311 				ND_PRINT((ndo, "/srcrt"));
312 			if (flags & DVMRP_NF_QUERIER)
313 				ND_PRINT((ndo, "/querier"));
314 			if (flags & DVMRP_NF_DISABLED)
315 				ND_PRINT((ndo, "/disabled"));
316 			if (flags & DVMRP_NF_DOWN)
317 				ND_PRINT((ndo, "/down"));
318 			ND_PRINT((ndo, ")]"));
319 			bp += 4;
320 			len -= 4;
321 		}
322 		if (ncount != -1) {
323 			ND_PRINT((ndo, " [|]"));
324 			return (0);
325 		}
326 	}
327 	return (0);
328 trunc:
329 	return (-1);
330 }
331 
332 static int
print_prune(netdissect_options * ndo,register const u_char * bp)333 print_prune(netdissect_options *ndo,
334             register const u_char *bp)
335 {
336 	ND_TCHECK2(bp[0], 12);
337 	ND_PRINT((ndo, " src %s grp %s", ipaddr_string(ndo, bp), ipaddr_string(ndo, bp + 4)));
338 	bp += 8;
339 	ND_PRINT((ndo, " timer "));
340 	relts_print(ndo, EXTRACT_32BITS(bp));
341 	return (0);
342 trunc:
343 	return (-1);
344 }
345 
346 static int
print_graft(netdissect_options * ndo,register const u_char * bp)347 print_graft(netdissect_options *ndo,
348             register const u_char *bp)
349 {
350 	ND_TCHECK2(bp[0], 8);
351 	ND_PRINT((ndo, " src %s grp %s", ipaddr_string(ndo, bp), ipaddr_string(ndo, bp + 4)));
352 	return (0);
353 trunc:
354 	return (-1);
355 }
356 
357 static int
print_graft_ack(netdissect_options * ndo,register const u_char * bp)358 print_graft_ack(netdissect_options *ndo,
359                 register const u_char *bp)
360 {
361 	ND_TCHECK2(bp[0], 8);
362 	ND_PRINT((ndo, " src %s grp %s", ipaddr_string(ndo, bp), ipaddr_string(ndo, bp + 4)));
363 	return (0);
364 trunc:
365 	return (-1);
366 }
367