]> The Tcpdump Group git mirrors - tcpdump/blob - print-aodv.c
Add initial bounds check, get rid of union aodv.
[tcpdump] / print-aodv.c
1 /*
2 * Copyright (c) 2003 Bruce M. Simpson <bms@spc.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bruce M. Simpson.
16 * 4. Neither the name of Bruce M. Simpson nor the names of co-
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bruce M. Simpson AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Bruce M. Simpson OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #ifndef lint
34 static const char rcsid[] _U_ =
35 "@(#) $Header: /tcpdump/master/tcpdump/print-aodv.c,v 1.11 2004-03-24 00:30:19 guy Exp $ (LBL)";
36 #endif
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <tcpdump-stdinc.h>
43
44 #include <stddef.h>
45 #include <stdio.h>
46 #include <ctype.h>
47 #include <string.h>
48
49 #include "interface.h"
50 #include "addrtoname.h"
51 #include "extract.h" /* must come after interface.h */
52
53 #include "aodv.h"
54
55 static void
56 aodv_extension(const struct aodv_ext *ep, u_int length)
57 {
58 u_int i;
59 const struct aodv_hello *ah;
60
61 switch (ep->type) {
62 case AODV_EXT_HELLO:
63 if (snapend < (u_char *) ep) {
64 printf(" [|hello]");
65 return;
66 }
67 i = min(length, (u_int)(snapend - (u_char *)ep));
68 if (i < sizeof(struct aodv_hello)) {
69 printf(" [|hello]");
70 return;
71 }
72 i -= sizeof(struct aodv_hello);
73 ah = (void *)ep;
74 printf("\n\text HELLO %ld ms",
75 (unsigned long)EXTRACT_32BITS(&ah->interval));
76 break;
77
78 default:
79 printf("\n\text %u %u", ep->type, ep->length);
80 break;
81 }
82 }
83
84 static void
85 aodv_rreq(const struct aodv_rreq *ap, const u_char *dat, u_int length)
86 {
87 u_int i;
88
89 if (snapend < dat) {
90 printf(" [|aodv]");
91 return;
92 }
93 i = min(length, (u_int)(snapend - dat));
94 if (i < sizeof(*ap)) {
95 printf(" [|rreq]");
96 return;
97 }
98 i -= sizeof(*ap);
99 printf(" rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
100 "\tdst %s seq %lu src %s seq %lu", length,
101 ap->rreq_type & RREQ_JOIN ? "[J]" : "",
102 ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
103 ap->rreq_type & RREQ_GRAT ? "[G]" : "",
104 ap->rreq_type & RREQ_DEST ? "[D]" : "",
105 ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
106 ap->rreq_hops,
107 (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
108 ipaddr_string(&ap->rreq_da),
109 (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
110 ipaddr_string(&ap->rreq_oa),
111 (unsigned long)EXTRACT_32BITS(&ap->rreq_os));
112 if (i >= sizeof(struct aodv_ext))
113 aodv_extension((void *)(ap + 1), i);
114 }
115
116 static void
117 aodv_rrep(const struct aodv_rrep *ap, const u_char *dat, u_int length)
118 {
119 u_int i;
120
121 if (snapend < dat) {
122 printf(" [|aodv]");
123 return;
124 }
125 i = min(length, (u_int)(snapend - dat));
126 if (i < sizeof(*ap)) {
127 printf(" [|rrep]");
128 return;
129 }
130 i -= sizeof(*ap);
131 printf(" rrep %u %s%sprefix %u hops %u\n"
132 "\tdst %s dseq %lu src %s %lu ms", length,
133 ap->rrep_type & RREP_REPAIR ? "[R]" : "",
134 ap->rrep_type & RREP_ACK ? "[A] " : " ",
135 ap->rrep_ps & RREP_PREFIX_MASK,
136 ap->rrep_hops,
137 ipaddr_string(&ap->rrep_da),
138 (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
139 ipaddr_string(&ap->rrep_oa),
140 (unsigned long)EXTRACT_32BITS(&ap->rrep_life));
141 if (i >= sizeof(struct aodv_ext))
142 aodv_extension((void *)(ap + 1), i);
143 }
144
145 static void
146 aodv_rerr(const struct aodv_rerr *ap, const u_char *dat, u_int length)
147 {
148 u_int i;
149 const struct rerr_unreach *dp = NULL;
150 int n, trunc;
151
152 if (snapend < dat) {
153 printf(" [|aodv]");
154 return;
155 }
156 i = min(length, (u_int)(snapend - dat));
157 if (i < offsetof(struct aodv_rerr, r)) {
158 printf(" [|rerr]");
159 return;
160 }
161 i -= offsetof(struct aodv_rerr, r);
162 dp = &ap->r.dest[0];
163 n = ap->rerr_dc * sizeof(ap->r.dest[0]);
164 printf(" rerr %s [items %u] [%u]:",
165 ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
166 ap->rerr_dc, length);
167 trunc = n - (i/sizeof(ap->r.dest[0]));
168 for (; i >= sizeof(ap->r.dest[0]);
169 ++dp, i -= sizeof(ap->r.dest[0])) {
170 printf(" {%s}(%ld)", ipaddr_string(&dp->u_da),
171 (unsigned long)EXTRACT_32BITS(&dp->u_ds));
172 }
173 if (trunc)
174 printf("[|rerr]");
175 }
176
177 static void
178 #ifdef INET6
179 aodv_v6_rreq(const struct aodv_rreq6 *ap, const u_char *dat, u_int length)
180 #else
181 aodv_v6_rreq(const struct aodv_rreq6 *ap _U_, const u_char *dat _U_, u_int length)
182 #endif
183 {
184 #ifdef INET6
185 u_int i;
186
187 if (snapend < dat) {
188 printf(" [|aodv]");
189 return;
190 }
191 i = min(length, (u_int)(snapend - dat));
192 if (i < sizeof(*ap)) {
193 printf(" [|rreq6]");
194 return;
195 }
196 i -= sizeof(*ap);
197 printf(" v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
198 "\tdst %s seq %lu src %s seq %lu", length,
199 ap->rreq_type & RREQ_JOIN ? "[J]" : "",
200 ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
201 ap->rreq_type & RREQ_GRAT ? "[G]" : "",
202 ap->rreq_type & RREQ_DEST ? "[D]" : "",
203 ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
204 ap->rreq_hops,
205 (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
206 ip6addr_string(&ap->rreq_da),
207 (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
208 ip6addr_string(&ap->rreq_oa),
209 (unsigned long)EXTRACT_32BITS(&ap->rreq_os));
210 if (i >= sizeof(struct aodv_ext))
211 aodv_extension((void *)(ap + 1), i);
212 #else
213 printf(" v6 rreq %u", length);
214 #endif
215 }
216
217 static void
218 #ifdef INET6
219 aodv_v6_rrep(const struct aodv_rrep6 *ap, const u_char *dat, u_int length)
220 #else
221 aodv_v6_rrep(const struct aodv_rrep6 *ap _U_, const u_char *dat _U_, u_int length)
222 #endif
223 {
224 #ifdef INET6
225 u_int i;
226
227 if (snapend < dat) {
228 printf(" [|aodv]");
229 return;
230 }
231 i = min(length, (u_int)(snapend - dat));
232 if (i < sizeof(*ap)) {
233 printf(" [|rrep6]");
234 return;
235 }
236 i -= sizeof(*ap);
237 printf(" rrep %u %s%sprefix %u hops %u\n"
238 "\tdst %s dseq %lu src %s %lu ms", length,
239 ap->rrep_type & RREP_REPAIR ? "[R]" : "",
240 ap->rrep_type & RREP_ACK ? "[A] " : " ",
241 ap->rrep_ps & RREP_PREFIX_MASK,
242 ap->rrep_hops,
243 ip6addr_string(&ap->rrep_da),
244 (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
245 ip6addr_string(&ap->rrep_oa),
246 (unsigned long)EXTRACT_32BITS(&ap->rrep_life));
247 if (i >= sizeof(struct aodv_ext))
248 aodv_extension((void *)(ap + 1), i);
249 #else
250 printf(" rrep %u", length);
251 #endif
252 }
253
254 static void
255 #ifdef INET6
256 aodv_v6_rerr(const struct aodv_rerr *ap, u_int length)
257 #else
258 aodv_v6_rerr(const struct aodv_rerr *ap _U_, u_int length)
259 #endif
260 {
261 #ifdef INET6
262 const struct rerr_unreach6 *dp6 = NULL;
263 int i, j, n, trunc;
264
265 i = length - offsetof(struct aodv_rerr, r);
266 j = sizeof(ap->r.dest6[0]);
267 dp6 = &ap->r.dest6[0];
268 n = ap->rerr_dc * j;
269 printf(" rerr %s [items %u] [%u]:",
270 ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
271 ap->rerr_dc, length);
272 trunc = n - (i/j);
273 for (; i -= j >= 0; ++dp6) {
274 printf(" {%s}(%ld)", ip6addr_string(&dp6->u_da),
275 (unsigned long)EXTRACT_32BITS(&dp6->u_ds));
276 }
277 if (trunc)
278 printf("[|rerr]");
279 #else
280 printf(" rerr %u", length);
281 #endif
282 }
283
284 static void
285 #ifdef INET6
286 aodv_v6_draft_01_rreq(const struct aodv_rreq6_draft_01 *ap, const u_char *dat, u_int length)
287 #else
288 aodv_v6_draft_01_rreq(const struct aodv_rreq6_draft_01 *ap _U_, const u_char *dat _U_, u_int length)
289 #endif
290 {
291 #ifdef INET6
292 u_int i;
293
294 if (snapend < dat) {
295 printf(" [|aodv]");
296 return;
297 }
298 i = min(length, (u_int)(snapend - dat));
299 if (i < sizeof(*ap)) {
300 printf(" [|rreq6]");
301 return;
302 }
303 i -= sizeof(*ap);
304 printf(" rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
305 "\tdst %s seq %lu src %s seq %lu", length,
306 ap->rreq_type & RREQ_JOIN ? "[J]" : "",
307 ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
308 ap->rreq_type & RREQ_GRAT ? "[G]" : "",
309 ap->rreq_type & RREQ_DEST ? "[D]" : "",
310 ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
311 ap->rreq_hops,
312 (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
313 ip6addr_string(&ap->rreq_da),
314 (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
315 ip6addr_string(&ap->rreq_oa),
316 (unsigned long)EXTRACT_32BITS(&ap->rreq_os));
317 if (i >= sizeof(struct aodv_ext))
318 aodv_extension((void *)(ap + 1), i);
319 #else
320 printf(" rreq %u", length);
321 #endif
322 }
323
324 static void
325 #ifdef INET6
326 aodv_v6_draft_01_rrep(const struct aodv_rrep6_draft_01 *ap, const u_char *dat, u_int length)
327 #else
328 aodv_v6_draft_01_rrep(const struct aodv_rrep6_draft_01 *ap _U_, const u_char *dat _U_, u_int length)
329 #endif
330 {
331 #ifdef INET6
332 u_int i;
333
334 if (snapend < dat) {
335 printf(" [|aodv]");
336 return;
337 }
338 i = min(length, (u_int)(snapend - dat));
339 if (i < sizeof(*ap)) {
340 printf(" [|rrep6]");
341 return;
342 }
343 i -= sizeof(*ap);
344 printf(" rrep %u %s%sprefix %u hops %u\n"
345 "\tdst %s dseq %lu src %s %lu ms", length,
346 ap->rrep_type & RREP_REPAIR ? "[R]" : "",
347 ap->rrep_type & RREP_ACK ? "[A] " : " ",
348 ap->rrep_ps & RREP_PREFIX_MASK,
349 ap->rrep_hops,
350 ip6addr_string(&ap->rrep_da),
351 (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
352 ip6addr_string(&ap->rrep_oa),
353 (unsigned long)EXTRACT_32BITS(&ap->rrep_life));
354 if (i >= sizeof(struct aodv_ext))
355 aodv_extension((void *)(ap + 1), i);
356 #else
357 printf(" rrep %u", length);
358 #endif
359 }
360
361 static void
362 #ifdef INET6
363 aodv_v6_draft_01_rerr(const struct aodv_rerr *ap, u_int length)
364 #else
365 aodv_v6_draft_01_rerr(const struct aodv_rerr *ap _U_, u_int length)
366 #endif
367 {
368 #ifdef INET6
369 const struct rerr_unreach6_draft_01 *dp6 = NULL;
370 int i, j, n, trunc;
371
372 i = length - offsetof(struct aodv_rerr, r);
373 j = sizeof(ap->r.dest6_draft_01[0]);
374 dp6 = &ap->r.dest6_draft_01[0];
375 n = ap->rerr_dc * j;
376 printf(" rerr %s [items %u] [%u]:",
377 ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
378 ap->rerr_dc, length);
379 trunc = n - (i/j);
380 for (; i -= j >= 0; ++dp6) {
381 printf(" {%s}(%ld)", ip6addr_string(&dp6->u_da),
382 (unsigned long)EXTRACT_32BITS(&dp6->u_ds));
383 }
384 if (trunc)
385 printf("[|rerr]");
386 #else
387 printf(" rerr %u", length);
388 #endif
389 }
390
391 void
392 aodv_print(const u_char *dat, u_int length, int is_ip6)
393 {
394 uint8_t msg_type;
395
396 /*
397 * The message type is the first byte; make sure we have it
398 * and then fetch it.
399 */
400 TCHECK(*dat);
401 msg_type = *dat;
402 printf(" aodv");
403
404 switch (msg_type) {
405
406 case AODV_RREQ:
407 if (is_ip6)
408 aodv_v6_rreq((const struct aodv_rreq6 *)dat, dat, length);
409 else
410 aodv_rreq((const struct aodv_rreq *)dat, dat, length);
411 break;
412
413 case AODV_RREP:
414 if (is_ip6)
415 aodv_v6_rrep((const struct aodv_rrep6 *)dat, dat, length);
416 else
417 aodv_rrep((const struct aodv_rrep *)dat, dat, length);
418 break;
419
420 case AODV_RERR:
421 if (is_ip6)
422 aodv_v6_rerr((const struct aodv_rerr *)dat, length);
423 else
424 aodv_rerr((const struct aodv_rerr *)dat, dat, length);
425 break;
426
427 case AODV_RREP_ACK:
428 printf(" rrep-ack %u", length);
429 break;
430
431 case AODV_V6_DRAFT_01_RREQ:
432 aodv_v6_draft_01_rreq((const struct aodv_rreq6_draft_01 *)dat, dat, length);
433 break;
434
435 case AODV_V6_DRAFT_01_RREP:
436 aodv_v6_draft_01_rrep((const struct aodv_rrep6_draft_01 *)dat, dat, length);
437 break;
438
439 case AODV_V6_DRAFT_01_RERR:
440 aodv_v6_draft_01_rerr((const struct aodv_rerr *)dat, length);
441 break;
442
443 case AODV_V6_DRAFT_01_RREP_ACK:
444 printf(" rrep-ack %u", length);
445 break;
446
447 default:
448 printf(" type %u %u", msg_type, length);
449 }
450 return;
451
452 trunc:
453 printf(" [|aodv]");
454 }