]> The Tcpdump Group git mirrors - tcpdump/blob - print-icmp6.c
Bring in KAME IPv6 tcpdump. replaces esp/ah/isakmp decoder.
[tcpdump] / print-icmp6.c
1 /*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
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 #ifndef lint
23 static const char rcsid[] =
24 "@(#) /master/usr.sbin/tcpdump/tcpdump/print-icmp.c,v 2.1 1995/02/03 18:14:42 polk Exp (LBL)";
25 #endif
26
27 #ifdef INET6
28
29 #include <ctype.h>
30
31 #include <sys/param.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35
36 #include <net/if.h>
37
38 #include <netinet/in.h>
39 #include <netinet/if_ether.h>
40 #include <netinet/in_systm.h>
41 #include <netinet/ip.h>
42 #include <netinet/ip_icmp.h>
43 #include <netinet/ip_var.h>
44 #include <netinet/udp.h>
45 #include <netinet/udp_var.h>
46 #include <netinet/tcp.h>
47
48 #include <arpa/inet.h>
49
50 #include <stdio.h>
51
52 #include <netinet/ip6.h>
53 #include <netinet/icmp6.h>
54
55 #include "interface.h"
56 #include "addrtoname.h"
57
58 void icmp6_opt_print(const u_char *, int);
59 void mld6_print(const u_char *);
60
61 void
62 icmp6_print(register const u_char *bp, register const u_char *bp2)
63 {
64 register const struct icmp6_hdr *dp;
65 register const struct ip6_hdr *ip;
66 register const char *str;
67 register const struct ip6_hdr *oip;
68 register const struct udphdr *ouh;
69 register int hlen, dport;
70 register const u_char *ep;
71 char buf[256];
72 int icmp6len;
73
74 #if 0
75 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
76 #endif
77
78 dp = (struct icmp6_hdr *)bp;
79 ip = (struct ip6_hdr *)bp2;
80 oip = (struct ip6_hdr *)(dp + 1);
81 str = buf;
82 /* 'ep' points to the end of avaible data. */
83 ep = snapend;
84 if (ip->ip6_plen)
85 icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) -
86 (bp - bp2));
87 else /* XXX: jumbo payload case... */
88 icmp6len = snapend - bp;
89
90 #if 0
91 (void)printf("%s > %s: ",
92 ip6addr_string(&ip->ip6_src),
93 ip6addr_string(&ip->ip6_dst));
94 #endif
95
96 TCHECK(dp->icmp6_code);
97 switch(dp->icmp6_type) {
98 case ICMP6_DST_UNREACH:
99 TCHECK(oip->ip6_dst);
100 switch (dp->icmp6_code) {
101 case ICMP6_DST_UNREACH_NOROUTE:
102 printf("icmp6: %s unreachable route",
103 ip6addr_string(&oip->ip6_dst));
104 break;
105 case ICMP6_DST_UNREACH_ADMIN:
106 printf("icmp6: %s unreachable prohibited",
107 ip6addr_string(&oip->ip6_dst));
108 break;
109 #ifdef ICMP6_DST_UNREACH_BEYONDSCOPE
110 case ICMP6_DST_UNREACH_BEYONDSCOPE:
111 #else
112 case ICMP6_DST_UNREACH_NOTNEIGHBOR:
113 #endif
114 printf("icmp6: %s beyond scope of source address %s",
115 ip6addr_string(&oip->ip6_dst),
116 ip6addr_string(&oip->ip6_src));
117 break;
118 case ICMP6_DST_UNREACH_ADDR:
119 printf("icmp6: %s unreachable address",
120 ip6addr_string(&oip->ip6_dst));
121 break;
122 case ICMP6_DST_UNREACH_NOPORT:
123 TCHECK(oip->ip6_nxt);
124 hlen = sizeof(struct ip6_hdr);
125 ouh = (struct udphdr *)(((u_char *)oip) + hlen);
126 dport = ntohs(ouh->uh_dport);
127 switch (oip->ip6_nxt) {
128 case IPPROTO_TCP:
129 printf("icmp6: %s tcp port %s unreachable",
130 ip6addr_string(&oip->ip6_dst),
131 tcpport_string(dport));
132 break;
133 case IPPROTO_UDP:
134 printf("icmp6: %s udp port %s unreachable",
135 ip6addr_string(&oip->ip6_dst),
136 udpport_string(dport));
137 break;
138 default:
139 printf("icmp6: %s protocol %d port %d unreachable",
140 ip6addr_string(&oip->ip6_dst),
141 oip->ip6_nxt, dport);
142 break;
143 }
144 break;
145 default:
146 printf("icmp6: %s unreachable code-#%d",
147 ip6addr_string(&oip->ip6_dst),
148 dp->icmp6_code);
149 break;
150 }
151 break;
152 case ICMP6_PACKET_TOO_BIG:
153 TCHECK(dp->icmp6_mtu);
154 printf("icmp6: too big %u\n", (u_int32_t)ntohl(dp->icmp6_mtu));
155 break;
156 case ICMP6_TIME_EXCEEDED:
157 TCHECK(oip->ip6_dst);
158 switch (dp->icmp6_code) {
159 case ICMP6_TIME_EXCEED_TRANSIT:
160 printf("icmp6: time exceeded in-transit for %s",
161 ip6addr_string(&oip->ip6_dst));
162 break;
163 case ICMP6_TIME_EXCEED_REASSEMBLY:
164 printf("icmp6: ip6 reassembly time exceeded");
165 break;
166 default:
167 printf("icmp6: time exceeded code-#%d",
168 dp->icmp6_code);
169 break;
170 }
171 break;
172 case ICMP6_PARAM_PROB:
173 TCHECK(oip->ip6_dst);
174 switch (dp->icmp6_code) {
175 case ICMP6_PARAMPROB_HEADER:
176 printf("icmp6: parameter problem errorneous - octet %u\n",
177 (u_int32_t)ntohl(dp->icmp6_pptr));
178 break;
179 case ICMP6_PARAMPROB_NEXTHEADER:
180 printf("icmp6: parameter problem next header - octet %u\n",
181 (u_int32_t)ntohl(dp->icmp6_pptr));
182 break;
183 case ICMP6_PARAMPROB_OPTION:
184 printf("icmp6: parameter problem option - octet %u\n",
185 (u_int32_t)ntohl(dp->icmp6_pptr));
186 break;
187 default:
188 printf("icmp6: parameter problem code-#%d",
189 dp->icmp6_code);
190 break;
191 }
192 break;
193 case ICMP6_ECHO_REQUEST:
194 printf("icmp6: echo request");
195 break;
196 case ICMP6_ECHO_REPLY:
197 printf("icmp6: echo reply");
198 break;
199 case ICMP6_MEMBERSHIP_QUERY:
200 printf("icmp6: multicast listener query ");
201 mld6_print((const u_char *)dp);
202 break;
203 case ICMP6_MEMBERSHIP_REPORT:
204 printf("icmp6: multicast listener report ");
205 mld6_print((const u_char *)dp);
206 break;
207 case ICMP6_MEMBERSHIP_REDUCTION:
208 printf("icmp6: multicast listener done ");
209 mld6_print((const u_char *)dp);
210 break;
211 case ND_ROUTER_SOLICIT:
212 printf("icmp6: router solicitation ");
213 if (vflag) {
214 #define RTSOLLEN 8
215 icmp6_opt_print((const u_char *)dp + RTSOLLEN,
216 icmp6len - RTSOLLEN);
217 }
218 break;
219 case ND_ROUTER_ADVERT:
220 printf("icmp6: router advertisement");
221 if (vflag) {
222 struct nd_router_advert *p;
223
224 p = (struct nd_router_advert *)dp;
225 TCHECK(p->nd_ra_retransmit);
226 printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit);
227 if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
228 printf("M");
229 if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
230 printf("O");
231 if (p->nd_ra_flags_reserved != 0)
232 printf(" ");
233 printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime));
234 printf("reachable_time=%u, ",
235 (u_int32_t)ntohl(p->nd_ra_reachable));
236 printf("retrans_time=%u)",
237 (u_int32_t)ntohl(p->nd_ra_retransmit));
238 #define RTADVLEN 16
239 icmp6_opt_print((const u_char *)dp + RTADVLEN,
240 icmp6len - RTADVLEN);
241 }
242 break;
243 case ND_NEIGHBOR_SOLICIT:
244 {
245 struct nd_neighbor_solicit *p;
246 p = (struct nd_neighbor_solicit *)dp;
247 TCHECK(p->nd_ns_target);
248 printf("icmp6: neighbor sol: who has %s",
249 ip6addr_string(&p->nd_ns_target));
250 if (vflag) {
251 #define NDSOLLEN 24
252 icmp6_opt_print((const u_char *)dp + NDSOLLEN,
253 icmp6len - NDSOLLEN);
254 }
255 }
256 break;
257 case ND_NEIGHBOR_ADVERT:
258 {
259 struct nd_neighbor_advert *p;
260
261 p = (struct nd_neighbor_advert *)dp;
262 TCHECK(p->nd_na_target);
263 printf("icmp6: neighbor adv: tgt is %s",
264 ip6addr_string(&p->nd_na_target));
265 if (vflag) {
266 #define ND_NA_FLAG_ALL \
267 (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
268 /* we don't need ntohl() here. see advanced-api-04. */
269 if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) {
270 #undef ND_NA_FLAG_ALL
271 u_int32_t flags;
272
273 flags = p->nd_na_flags_reserved;
274 printf("(");
275 if (flags & ND_NA_FLAG_ROUTER)
276 printf("R");
277 if (flags & ND_NA_FLAG_SOLICITED)
278 printf("S");
279 if (flags & ND_NA_FLAG_OVERRIDE)
280 printf("O");
281 printf(")");
282 }
283 #define NDADVLEN 24
284 icmp6_opt_print((const u_char *)dp + NDADVLEN,
285 icmp6len - NDADVLEN);
286 }
287 }
288 break;
289 case ND_REDIRECT:
290 {
291 #define RDR(i) ((struct nd_redirect *)(i))
292 char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN];
293
294 TCHECK(RDR(dp)->nd_rd_dst);
295 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target,
296 tgtbuf, INET6_ADDRSTRLEN);
297 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst,
298 dstbuf, INET6_ADDRSTRLEN);
299 printf("icmp6: redirect %s to %s", dstbuf, tgtbuf);
300 #define REDIRECTLEN 40
301 if (vflag) {
302 icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
303 icmp6len - REDIRECTLEN);
304 }
305 break;
306 }
307 case ICMP6_ROUTER_RENUMBERING:
308 switch (dp->icmp6_code) {
309 case ICMP6_ROUTER_RENUMBERING_COMMAND:
310 printf("icmp6: router renum command");
311 break;
312 case ICMP6_ROUTER_RENUMBERING_RESULT:
313 printf("icmp6: router renum result");
314 break;
315 default:
316 printf("icmp6: router renum code-#%d", dp->icmp6_code);
317 break;
318 }
319 break;
320 #ifdef ICMP6_WRUREQUEST
321 case ICMP6_WRUREQUEST: /*ICMP6_FQDN_QUERY*/
322 {
323 int siz;
324 siz = ep - (u_char *)(dp + 1);
325 if (siz == 4)
326 printf("icmp6: who-are-you request");
327 else {
328 printf("icmp6: FQDN request");
329 if (vflag) {
330 if (siz < 8)
331 printf("?(icmp6_data %d bytes)", siz);
332 else if (8 < siz)
333 printf("?(extra %d bytes)", siz - 8);
334 }
335 }
336 break;
337 }
338 #endif /*ICMP6_WRUREQUEST*/
339 #ifdef ICMP6_WRUREPLY
340 case ICMP6_WRUREPLY: /*ICMP6_FQDN_REPLY*/
341 {
342 enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN;
343 u_char const *buf;
344 u_char const *cp = NULL;
345
346 buf = (u_char *)(dp + 1);
347
348 /* fair guess */
349 if (buf[12] == ep - buf - 13)
350 mode = FQDN;
351 else if (dp->icmp6_code == 1)
352 mode = FQDN;
353
354 /* wild guess */
355 if (mode == UNKNOWN) {
356 cp = buf + 4;
357 while (cp < ep) {
358 if (!isprint(*cp++))
359 mode = FQDN;
360 }
361 }
362 #ifndef abs
363 #define abs(a) ((0 < (a)) ? (a) : -(a))
364 #endif
365 if (mode == UNKNOWN && 2 < abs(buf[12] - (ep - buf - 13)))
366 mode = WRU;
367 if (mode == UNKNOWN)
368 mode = FQDN;
369
370 if (mode == WRU) {
371 cp = buf + 4;
372 printf("icmp6: who-are-you reply(\"");
373 } else if (mode == FQDN) {
374 cp = buf + 13;
375 printf("icmp6: FQDN reply(\"");
376 }
377 for (; cp < ep; cp++)
378 printf((isprint(*cp) ? "%c" : "\\%03o"), *cp);
379 printf("\"");
380 if (vflag) {
381 printf(",%s", mode == FQDN ? "FQDN" : "WRU");
382 if (mode == FQDN) {
383 long ttl;
384 ttl = (long)ntohl(*(u_long *)&buf[8]);
385 if (dp->icmp6_code == 1)
386 printf(",TTL=unknown");
387 else if (ttl < 0)
388 printf(",TTL=%ld:invalid", ttl);
389 else
390 printf(",TTL=%ld", ttl);
391 if (buf[12] != ep - buf - 13) {
392 (void)printf(",invalid namelen:%d/%u",
393 buf[12],
394 (unsigned int)(ep - buf - 13));
395 }
396 }
397 }
398 printf(")");
399 break;
400 }
401 #endif /*ICMP6_WRUREPLY*/
402 default:
403 printf("icmp6: type-#%d", dp->icmp6_type);
404 break;
405 }
406 return;
407 trunc:
408 fputs("[|icmp6]", stdout);
409 #if 0
410 #undef TCHECK
411 #endif
412 }
413
414 void
415 icmp6_opt_print(register const u_char *bp, int resid)
416 {
417 register const struct nd_opt_hdr *op;
418 register const struct nd_opt_hdr *opl; /* why there's no struct? */
419 register const struct nd_opt_prefix_info *opp;
420 register const struct icmp6_opts_redirect *opr;
421 register const struct nd_opt_mtu *opm;
422 register const u_char *ep;
423 int opts_len;
424 #if 0
425 register const struct ip6_hdr *ip;
426 register const char *str;
427 register const struct ip6_hdr *oip;
428 register const struct udphdr *ouh;
429 register int hlen, dport;
430 char buf[256];
431 #endif
432
433 #if 0
434 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
435 #endif
436 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
437
438 op = (struct nd_opt_hdr *)bp;
439 #if 0
440 ip = (struct ip6_hdr *)bp2;
441 oip = &dp->icmp6_ip6;
442 str = buf;
443 #endif
444 /* 'ep' points to the end of avaible data. */
445 ep = snapend;
446
447 ECHECK(op->nd_opt_len);
448 if (resid <= 0)
449 return;
450 switch(op->nd_opt_type) {
451 case ND_OPT_SOURCE_LINKADDR:
452 opl = (struct nd_opt_hdr *)op;
453 #if 1
454 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
455 goto trunc;
456 #else
457 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
458 #endif
459 printf("(src lladdr: %s",
460 etheraddr_string((u_char *)(opl + 1)));
461 if (opl->nd_opt_len != 1)
462 printf("!");
463 printf(")");
464 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
465 resid - (op->nd_opt_len << 3));
466 break;
467 case ND_OPT_TARGET_LINKADDR:
468 opl = (struct nd_opt_hdr *)op;
469 #if 1
470 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
471 goto trunc;
472 #else
473 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
474 #endif
475 printf("(tgt lladdr: %s",
476 etheraddr_string((u_char *)(opl + 1)));
477 if (opl->nd_opt_len != 1)
478 printf("!");
479 printf(")");
480 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
481 resid - (op->nd_opt_len << 3));
482 break;
483 case ND_OPT_PREFIX_INFORMATION:
484 opp = (struct nd_opt_prefix_info *)op;
485 TCHECK(opp->nd_opt_pi_prefix);
486 printf("(prefix info: ");
487 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
488 printf("L");
489 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
490 printf("A");
491 if (opp->nd_opt_pi_flags_reserved)
492 printf(" ");
493 printf("valid_ltime=");
494 if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U)
495 printf("infinity");
496 else {
497 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time));
498 }
499 printf(", ");
500 printf("preffered_ltime=");
501 if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U)
502 printf("infinity");
503 else {
504 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time));
505 }
506 printf(", ");
507 printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix),
508 opp->nd_opt_pi_prefix_len);
509 if (opp->nd_opt_pi_len != 4)
510 printf("!");
511 printf(")");
512 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
513 resid - (op->nd_opt_len << 3));
514 break;
515 case ND_OPT_REDIRECTED_HEADER:
516 opr = (struct icmp6_opts_redirect *)op;
517 printf("(redirect)");
518 /* xxx */
519 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
520 resid - (op->nd_opt_len << 3));
521 break;
522 case ND_OPT_MTU:
523 opm = (struct nd_opt_mtu *)op;
524 TCHECK(opm->nd_opt_mtu_mtu);
525 printf("(mtu: ");
526 printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
527 if (opm->nd_opt_mtu_len != 1)
528 printf("!");
529 printf(")");
530 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
531 resid - (op->nd_opt_len << 3));
532 break;
533 default:
534 opts_len = op->nd_opt_len;
535 printf("(unknwon opt_type=%d, opt_len=%d)",
536 op->nd_opt_type, opts_len);
537 if (opts_len == 0)
538 opts_len = 1; /* XXX */
539 icmp6_opt_print((const u_char *)op + (opts_len << 3),
540 resid - (opts_len << 3));
541 break;
542 }
543 return;
544 trunc:
545 fputs("[ndp opt]", stdout);
546 return;
547 #if 0
548 #undef TCHECK
549 #endif
550 #undef ECHECK
551 }
552
553 void
554 mld6_print(register const u_char *bp)
555 {
556 register struct mld6_hdr *mp = (struct mld6_hdr *)bp;
557 register const u_char *ep;
558
559 /* 'ep' points to the end of avaible data. */
560 ep = snapend;
561
562 if ((u_char *)mp + sizeof(*mp) > ep)
563 return;
564
565 printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay));
566 printf("addr: %s", ip6addr_string(&mp->mld6_addr));
567
568 return;
569 }
570 #endif /* INET6 */