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