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