xref: /netbsd-src/external/bsd/tcpdump/dist/print-dvmrp.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 1995, 1996
30f74e101Schristos  *	The Regents of the University of California.  All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that: (1) source code distributions
70f74e101Schristos  * retain the above copyright notice and this paragraph in its entirety, (2)
80f74e101Schristos  * distributions including binary code include the above copyright notice and
90f74e101Schristos  * this paragraph in its entirety in the documentation or other materials
100f74e101Schristos  * provided with the distribution, and (3) all advertising materials mentioning
110f74e101Schristos  * features or use of this software display the following acknowledgement:
120f74e101Schristos  * ``This product includes software developed by the University of California,
130f74e101Schristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
140f74e101Schristos  * the University nor the names of its contributors may be used to endorse
150f74e101Schristos  * or promote products derived from this software without specific prior
160f74e101Schristos  * written permission.
170f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
180f74e101Schristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
190f74e101Schristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
200f74e101Schristos  */
210f74e101Schristos 
2211b3aaa1Schristos #include <sys/cdefs.h>
230f74e101Schristos #ifndef lint
24*26ba0b50Schristos __RCSID("$NetBSD: print-dvmrp.c,v 1.9 2024/09/02 16:15:31 christos Exp $");
250f74e101Schristos #endif
260f74e101Schristos 
27dc860a36Sspz /* \summary: Distance Vector Multicast Routing Protocol printer */
28dc860a36Sspz 
29c74ad251Schristos #include <config.h>
300f74e101Schristos 
31c74ad251Schristos #include "netdissect-stdinc.h"
320f74e101Schristos 
33fdccd7e4Schristos #include "netdissect.h"
340f74e101Schristos #include "extract.h"
350f74e101Schristos #include "addrtoname.h"
360f74e101Schristos 
370f74e101Schristos /*
38817e9a7eSchristos  * See: RFC 1075 and draft-ietf-idmr-dvmrp-v3
39817e9a7eSchristos  *
400f74e101Schristos  * DVMRP message types and flag values shamelessly stolen from
410f74e101Schristos  * mrouted/dvmrp.h.
420f74e101Schristos  */
430f74e101Schristos #define DVMRP_PROBE		1	/* for finding neighbors */
440f74e101Schristos #define DVMRP_REPORT		2	/* for reporting some or all routes */
450f74e101Schristos #define DVMRP_ASK_NEIGHBORS	3	/* sent by mapper, asking for a list */
460f74e101Schristos 					/* of this router's neighbors */
470f74e101Schristos #define DVMRP_NEIGHBORS		4	/* response to such a request */
480f74e101Schristos #define DVMRP_ASK_NEIGHBORS2	5	/* as above, want new format reply */
490f74e101Schristos #define DVMRP_NEIGHBORS2	6
500f74e101Schristos #define DVMRP_PRUNE		7	/* prune message */
510f74e101Schristos #define DVMRP_GRAFT		8	/* graft message */
520f74e101Schristos #define DVMRP_GRAFT_ACK		9	/* graft acknowledgement */
53c74ad251Schristos static const struct tok dvmrp_msgtype_str[] = {
54c74ad251Schristos 	{ DVMRP_PROBE,          "Probe"              },
55c74ad251Schristos 	{ DVMRP_REPORT,         "Report"             },
56c74ad251Schristos 	{ DVMRP_ASK_NEIGHBORS,  "Ask-neighbors(old)" },
57c74ad251Schristos 	{ DVMRP_NEIGHBORS,      "Neighbors(old)"     },
58c74ad251Schristos 	{ DVMRP_ASK_NEIGHBORS2, "Ask-neighbors2"     },
59c74ad251Schristos 	{ DVMRP_NEIGHBORS2,     "Neighbors2"         },
60c74ad251Schristos 	{ DVMRP_PRUNE,          "Prune"              },
61c74ad251Schristos 	{ DVMRP_GRAFT,          "Graft"              },
62c74ad251Schristos 	{ DVMRP_GRAFT_ACK,      "Graft-ACK"          },
63c74ad251Schristos 	{ 0, NULL }
64c74ad251Schristos };
650f74e101Schristos 
660f74e101Schristos /*
670f74e101Schristos  * 'flags' byte values in DVMRP_NEIGHBORS2 reply.
680f74e101Schristos  */
690f74e101Schristos #define DVMRP_NF_TUNNEL		0x01	/* neighbors reached via tunnel */
700f74e101Schristos #define DVMRP_NF_SRCRT		0x02	/* tunnel uses IP source routing */
710f74e101Schristos #define DVMRP_NF_DOWN		0x10	/* kernel state of interface */
720f74e101Schristos #define DVMRP_NF_DISABLED	0x20	/* administratively disabled */
730f74e101Schristos #define DVMRP_NF_QUERIER	0x40	/* I am the subnet's querier */
740f74e101Schristos 
75c74ad251Schristos static void print_probe(netdissect_options *, const u_char *, u_int);
76c74ad251Schristos static void print_report(netdissect_options *, const u_char *, u_int);
77c74ad251Schristos static void print_neighbors(netdissect_options *, const u_char *, u_int);
78c74ad251Schristos static void print_neighbors2(netdissect_options *, const u_char *, u_int, uint8_t, uint8_t);
790f74e101Schristos 
800f74e101Schristos void
81b3a00663Schristos dvmrp_print(netdissect_options *ndo,
82c74ad251Schristos             const u_char *bp, u_int len)
830f74e101Schristos {
84c74ad251Schristos 	u_char type;
85817e9a7eSchristos 	uint8_t major_version, minor_version;
860f74e101Schristos 
87c74ad251Schristos 	ndo->ndo_protocol = "dvmrp";
88c74ad251Schristos 	if (len < 8) {
89c74ad251Schristos 		ND_PRINT(" [length %u < 8]", len);
90c74ad251Schristos 		goto invalid;
91c74ad251Schristos 	}
920f74e101Schristos 
93c74ad251Schristos 	type = GET_U_1(bp + 1);
940f74e101Schristos 
950f74e101Schristos 	/* Skip IGMP header */
960f74e101Schristos 	bp += 8;
970f74e101Schristos 	len -= 8;
980f74e101Schristos 
99c74ad251Schristos 	ND_PRINT(" %s", tok2str(dvmrp_msgtype_str, "[type %u]", type));
1000f74e101Schristos 	switch (type) {
1010f74e101Schristos 
1020f74e101Schristos 	case DVMRP_PROBE:
103b3a00663Schristos 		if (ndo->ndo_vflag) {
104c74ad251Schristos 			print_probe(ndo, bp, len);
1050f74e101Schristos 		}
1060f74e101Schristos 		break;
1070f74e101Schristos 
1080f74e101Schristos 	case DVMRP_REPORT:
109b3a00663Schristos 		if (ndo->ndo_vflag > 1) {
110c74ad251Schristos 			print_report(ndo, bp, len);
1110f74e101Schristos 		}
1120f74e101Schristos 		break;
1130f74e101Schristos 
1140f74e101Schristos 	case DVMRP_NEIGHBORS:
115c74ad251Schristos 		print_neighbors(ndo, bp, len);
1160f74e101Schristos 		break;
1170f74e101Schristos 
1180f74e101Schristos 	case DVMRP_NEIGHBORS2:
1190f74e101Schristos 		/*
120817e9a7eSchristos 		 * extract version from IGMP group address field
1210f74e101Schristos 		 */
1220f74e101Schristos 		bp -= 4;
123c74ad251Schristos 		major_version = GET_U_1(bp + 3);
124c74ad251Schristos 		minor_version = GET_U_1(bp + 2);
1250f74e101Schristos 		bp += 4;
126c74ad251Schristos 		print_neighbors2(ndo, bp, len, major_version, minor_version);
1270f74e101Schristos 		break;
1280f74e101Schristos 
1290f74e101Schristos 	case DVMRP_PRUNE:
130c74ad251Schristos 		ND_PRINT(" src %s grp %s", GET_IPADDR_STRING(bp), GET_IPADDR_STRING(bp + 4));
131c74ad251Schristos 		ND_PRINT(" timer ");
132c74ad251Schristos 		unsigned_relts_print(ndo, GET_BE_U_4(bp + 8));
1330f74e101Schristos 		break;
1340f74e101Schristos 
1350f74e101Schristos 	case DVMRP_GRAFT:
136c74ad251Schristos 		ND_PRINT(" src %s grp %s", GET_IPADDR_STRING(bp), GET_IPADDR_STRING(bp + 4));
1370f74e101Schristos 		break;
1380f74e101Schristos 
1390f74e101Schristos 	case DVMRP_GRAFT_ACK:
140c74ad251Schristos 		ND_PRINT(" src %s grp %s", GET_IPADDR_STRING(bp), GET_IPADDR_STRING(bp + 4));
1410f74e101Schristos 		break;
1420f74e101Schristos 	}
1430f74e101Schristos 	return;
1440f74e101Schristos 
145c74ad251Schristos invalid:
146c74ad251Schristos 	nd_print_invalid(ndo);
1470f74e101Schristos }
1480f74e101Schristos 
149c74ad251Schristos static void
150b3a00663Schristos print_report(netdissect_options *ndo,
151c74ad251Schristos              const u_char *bp,
152c74ad251Schristos              u_int len)
1530f74e101Schristos {
154c74ad251Schristos 	uint32_t mask, origin;
155c74ad251Schristos 	u_int metric, done;
156c74ad251Schristos 	u_int i, width;
1570f74e101Schristos 
1580f74e101Schristos 	while (len > 0) {
1590f74e101Schristos 		if (len < 3) {
160c74ad251Schristos 			ND_PRINT(" [length %u < 3]", len);
161c74ad251Schristos 			goto invalid;
1620f74e101Schristos 		}
163c74ad251Schristos 		mask = (uint32_t)0xff << 24 | GET_U_1(bp) << 16 |
164c74ad251Schristos 			GET_U_1(bp + 1) << 8 | GET_U_1(bp + 2);
1650f74e101Schristos 		width = 1;
166c74ad251Schristos 		if (GET_U_1(bp))
1670f74e101Schristos 			width = 2;
168c74ad251Schristos 		if (GET_U_1(bp + 1))
1690f74e101Schristos 			width = 3;
170c74ad251Schristos 		if (GET_U_1(bp + 2))
1710f74e101Schristos 			width = 4;
1720f74e101Schristos 
173c74ad251Schristos 		ND_PRINT("\n\tMask %s", intoa(htonl(mask)));
1740f74e101Schristos 		bp += 3;
1750f74e101Schristos 		len -= 3;
1760f74e101Schristos 		do {
1770f74e101Schristos 			if (len < width + 1) {
178c74ad251Schristos 				ND_PRINT("\n\t  [Truncated Report]");
179c74ad251Schristos 				goto invalid;
1800f74e101Schristos 			}
1810f74e101Schristos 			origin = 0;
1820f74e101Schristos 			for (i = 0; i < width; ++i) {
183c74ad251Schristos 				origin = origin << 8 | GET_U_1(bp);
184c74ad251Schristos 				bp++;
1850f74e101Schristos 			}
1860f74e101Schristos 			for ( ; i < 4; ++i)
1870f74e101Schristos 				origin <<= 8;
1880f74e101Schristos 
189c74ad251Schristos 			metric = GET_U_1(bp);
190c74ad251Schristos 			bp++;
1910f74e101Schristos 			done = metric & 0x80;
1920f74e101Schristos 			metric &= 0x7f;
193c74ad251Schristos 			ND_PRINT("\n\t  %s metric %u", intoa(htonl(origin)),
194c74ad251Schristos 				metric);
1950f74e101Schristos 			len -= width + 1;
1960f74e101Schristos 		} while (!done);
1970f74e101Schristos 	}
198c74ad251Schristos 	return;
199c74ad251Schristos 
200c74ad251Schristos invalid:
201c74ad251Schristos 	nd_print_invalid(ndo);
2020f74e101Schristos }
2030f74e101Schristos 
204c74ad251Schristos static void
205b3a00663Schristos print_probe(netdissect_options *ndo,
206c74ad251Schristos             const u_char *bp,
207c74ad251Schristos             u_int len)
2080f74e101Schristos {
209c74ad251Schristos 	if (len < 4) {
210c74ad251Schristos 		ND_PRINT(" [full length %u < 4]", len);
211c74ad251Schristos 		goto invalid;
2120f74e101Schristos 	}
213c74ad251Schristos 	ND_PRINT(ndo->ndo_vflag > 1 ? "\n\t" : " ");
214c74ad251Schristos 	ND_PRINT("genid %u", GET_BE_U_4(bp));
215c74ad251Schristos 	if (ndo->ndo_vflag < 2)
216c74ad251Schristos 		return;
217c74ad251Schristos 
2180f74e101Schristos 	bp += 4;
2190f74e101Schristos 	len -= 4;
220c74ad251Schristos 	while (len > 0) {
221c74ad251Schristos 		if (len < 4) {
222c74ad251Schristos 			ND_PRINT("[remaining length %u < 4]", len);
223c74ad251Schristos 			goto invalid;
224c74ad251Schristos 		}
225c74ad251Schristos 		ND_PRINT("\n\tneighbor %s", GET_IPADDR_STRING(bp));
2260f74e101Schristos 		bp += 4; len -= 4;
2270f74e101Schristos 	}
228c74ad251Schristos 	return;
229c74ad251Schristos 
230c74ad251Schristos invalid:
231c74ad251Schristos 	nd_print_invalid(ndo);
2320f74e101Schristos }
2330f74e101Schristos 
234c74ad251Schristos static void
235b3a00663Schristos print_neighbors(netdissect_options *ndo,
236c74ad251Schristos                 const u_char *bp,
237c74ad251Schristos                 u_int len)
2380f74e101Schristos {
2390f74e101Schristos 	const u_char *laddr;
240c74ad251Schristos 	u_char metric;
241c74ad251Schristos 	u_char thresh;
242c74ad251Schristos 	int ncount;
2430f74e101Schristos 
244c74ad251Schristos 	while (len > 0) {
245c74ad251Schristos 		if (len < 7) {
246c74ad251Schristos 			ND_PRINT(" [length %u < 7]", len);
247c74ad251Schristos 			goto invalid;
248c74ad251Schristos 		}
2490f74e101Schristos 		laddr = bp;
2500f74e101Schristos 		bp += 4;
251c74ad251Schristos 		metric = GET_U_1(bp);
252c74ad251Schristos 		bp++;
253c74ad251Schristos 		thresh = GET_U_1(bp);
254c74ad251Schristos 		bp++;
255c74ad251Schristos 		ncount = GET_U_1(bp);
256c74ad251Schristos 		bp++;
2570f74e101Schristos 		len -= 7;
2580f74e101Schristos 		while (--ncount >= 0) {
259c74ad251Schristos 			if (len < 4) {
260c74ad251Schristos 				ND_PRINT(" [length %u < 4]", len);
261c74ad251Schristos 				goto invalid;
262c74ad251Schristos 			}
263c74ad251Schristos 			ND_PRINT(" [%s ->", GET_IPADDR_STRING(laddr));
264c74ad251Schristos 			ND_PRINT(" %s, (%u/%u)]",
265c74ad251Schristos 				   GET_IPADDR_STRING(bp), metric, thresh);
2660f74e101Schristos 			bp += 4;
2670f74e101Schristos 			len -= 4;
2680f74e101Schristos 		}
2690f74e101Schristos 	}
270c74ad251Schristos 	return;
271c74ad251Schristos 
272c74ad251Schristos invalid:
273c74ad251Schristos 	nd_print_invalid(ndo);
2740f74e101Schristos }
2750f74e101Schristos 
276c74ad251Schristos static void
277b3a00663Schristos print_neighbors2(netdissect_options *ndo,
278c74ad251Schristos                  const u_char *bp,
279c74ad251Schristos                  u_int len, uint8_t major_version,
280817e9a7eSchristos                  uint8_t minor_version)
2810f74e101Schristos {
2820f74e101Schristos 	const u_char *laddr;
283c74ad251Schristos 	u_char metric, thresh, flags;
284c74ad251Schristos 	int ncount;
2850f74e101Schristos 
286c74ad251Schristos 	ND_PRINT(" (v %u.%u):", major_version, minor_version);
2870f74e101Schristos 
288c74ad251Schristos 	while (len > 0) {
289c74ad251Schristos 		if (len < 8) {
290c74ad251Schristos 			ND_PRINT(" [length %u < 8]", len);
291c74ad251Schristos 			goto invalid;
292c74ad251Schristos 		}
2930f74e101Schristos 		laddr = bp;
2940f74e101Schristos 		bp += 4;
295c74ad251Schristos 		metric = GET_U_1(bp);
296c74ad251Schristos 		bp++;
297c74ad251Schristos 		thresh = GET_U_1(bp);
298c74ad251Schristos 		bp++;
299c74ad251Schristos 		flags = GET_U_1(bp);
300c74ad251Schristos 		bp++;
301c74ad251Schristos 		ncount = GET_U_1(bp);
302c74ad251Schristos 		bp++;
3030f74e101Schristos 		len -= 8;
304c74ad251Schristos 		while (--ncount >= 0 && len > 0) {
305c74ad251Schristos 			if (len < 4) {
306c74ad251Schristos 				ND_PRINT(" [length %u < 4]", len);
307c74ad251Schristos 				goto invalid;
308c74ad251Schristos 			}
309c74ad251Schristos 			ND_PRINT(" [%s -> ", GET_IPADDR_STRING(laddr));
310c74ad251Schristos 			ND_PRINT("%s (%u/%u", GET_IPADDR_STRING(bp),
311c74ad251Schristos 				     metric, thresh);
3120f74e101Schristos 			if (flags & DVMRP_NF_TUNNEL)
313c74ad251Schristos 				ND_PRINT("/tunnel");
3140f74e101Schristos 			if (flags & DVMRP_NF_SRCRT)
315c74ad251Schristos 				ND_PRINT("/srcrt");
3160f74e101Schristos 			if (flags & DVMRP_NF_QUERIER)
317c74ad251Schristos 				ND_PRINT("/querier");
3180f74e101Schristos 			if (flags & DVMRP_NF_DISABLED)
319c74ad251Schristos 				ND_PRINT("/disabled");
3200f74e101Schristos 			if (flags & DVMRP_NF_DOWN)
321c74ad251Schristos 				ND_PRINT("/down");
322c74ad251Schristos 			ND_PRINT(")]");
3230f74e101Schristos 			bp += 4;
3240f74e101Schristos 			len -= 4;
3250f74e101Schristos 		}
3260f74e101Schristos 		if (ncount != -1) {
327*26ba0b50Schristos 			ND_PRINT(" [ncount %d]", ncount);
328c74ad251Schristos 			goto invalid;
3290f74e101Schristos 		}
3300f74e101Schristos 	}
331c74ad251Schristos 	return;
3320f74e101Schristos 
333c74ad251Schristos invalid:
334c74ad251Schristos 	nd_print_invalid(ndo);
3350f74e101Schristos }
336