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