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