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