]> The Tcpdump Group git mirrors - tcpdump/blob - print-icmp6.c
search for getaddrinfo in -lsocket (Solaris 8)
[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.4 2000-03-13 05:00:04 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 if (p->nd_ra_flags_reserved & ND_RA_FLAG_HA)
236 printf("H");
237 if (p->nd_ra_flags_reserved != 0)
238 printf(" ");
239 printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime));
240 printf("reachable_time=%u, ",
241 (u_int32_t)ntohl(p->nd_ra_reachable));
242 printf("retrans_time=%u)",
243 (u_int32_t)ntohl(p->nd_ra_retransmit));
244 #define RTADVLEN 16
245 icmp6_opt_print((const u_char *)dp + RTADVLEN,
246 icmp6len - RTADVLEN);
247 }
248 break;
249 case ND_NEIGHBOR_SOLICIT:
250 {
251 struct nd_neighbor_solicit *p;
252 p = (struct nd_neighbor_solicit *)dp;
253 TCHECK(p->nd_ns_target);
254 printf("icmp6: neighbor sol: who has %s",
255 ip6addr_string(&p->nd_ns_target));
256 if (vflag) {
257 #define NDSOLLEN 24
258 icmp6_opt_print((const u_char *)dp + NDSOLLEN,
259 icmp6len - NDSOLLEN);
260 }
261 }
262 break;
263 case ND_NEIGHBOR_ADVERT:
264 {
265 struct nd_neighbor_advert *p;
266
267 p = (struct nd_neighbor_advert *)dp;
268 TCHECK(p->nd_na_target);
269 printf("icmp6: neighbor adv: tgt is %s",
270 ip6addr_string(&p->nd_na_target));
271 if (vflag) {
272 #define ND_NA_FLAG_ALL \
273 (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
274 /* we don't need ntohl() here. see advanced-api-04. */
275 if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) {
276 #undef ND_NA_FLAG_ALL
277 u_int32_t flags;
278
279 flags = p->nd_na_flags_reserved;
280 printf("(");
281 if (flags & ND_NA_FLAG_ROUTER)
282 printf("R");
283 if (flags & ND_NA_FLAG_SOLICITED)
284 printf("S");
285 if (flags & ND_NA_FLAG_OVERRIDE)
286 printf("O");
287 printf(")");
288 }
289 #define NDADVLEN 24
290 icmp6_opt_print((const u_char *)dp + NDADVLEN,
291 icmp6len - NDADVLEN);
292 }
293 }
294 break;
295 case ND_REDIRECT:
296 {
297 #define RDR(i) ((struct nd_redirect *)(i))
298 char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN];
299
300 TCHECK(RDR(dp)->nd_rd_dst);
301 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target,
302 tgtbuf, INET6_ADDRSTRLEN);
303 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst,
304 dstbuf, INET6_ADDRSTRLEN);
305 printf("icmp6: redirect %s to %s", dstbuf, tgtbuf);
306 #define REDIRECTLEN 40
307 if (vflag) {
308 icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
309 icmp6len - REDIRECTLEN);
310 }
311 break;
312 }
313 case ICMP6_ROUTER_RENUMBERING:
314 switch (dp->icmp6_code) {
315 case ICMP6_ROUTER_RENUMBERING_COMMAND:
316 printf("icmp6: router renum command");
317 break;
318 case ICMP6_ROUTER_RENUMBERING_RESULT:
319 printf("icmp6: router renum result");
320 break;
321 default:
322 printf("icmp6: router renum code-#%d", dp->icmp6_code);
323 break;
324 }
325 break;
326 #ifdef ICMP6_WRUREQUEST
327 case ICMP6_WRUREQUEST: /*ICMP6_FQDN_QUERY*/
328 {
329 int siz;
330 siz = ep - (u_char *)(dp + 1);
331 if (icmp6len > ep - (u_char *)dp) {
332 printf("[|icmp6: who-are-you/FQDN request]");
333 break;
334 }
335 if (siz == 4)
336 printf("icmp6: who-are-you request");
337 else {
338 printf("icmp6: FQDN request");
339 if (vflag && icmp6len == ep - (u_char *)dp) {
340 if (siz < 8)
341 printf("?(icmp6_data %d bytes)", siz);
342 else if (8 < siz)
343 printf("?(extra %d bytes)", siz - 8);
344 }
345 }
346 break;
347 }
348 #endif /*ICMP6_WRUREQUEST*/
349 #ifdef ICMP6_WRUREPLY
350 case ICMP6_WRUREPLY: /*ICMP6_FQDN_REPLY*/
351 {
352 enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN;
353 const u_char *buf;
354 const u_char *cp = NULL;
355 const char *modename = NULL;
356
357 buf = (u_char *)(dp + 1);
358
359 /* fair guess */
360 if (ep - buf > 12 && buf[12] == ep - buf - 13)
361 mode = FQDN;
362 else if (dp->icmp6_code == 1)
363 mode = FQDN;
364
365 /* wild guess */
366 if (mode == UNKNOWN && ep - buf > 4) {
367 cp = buf + 4;
368 while (cp < ep) {
369 if (!isprint(*cp++))
370 mode = FQDN;
371 }
372 }
373 #ifndef abs
374 #define abs(a) ((0 < (a)) ? (a) : -(a))
375 #endif
376 if (mode == UNKNOWN && ep - buf > 12 &&
377 2 < abs(buf[12] - (ep - buf - 13))) {
378 mode = WRU;
379 }
380 if (mode == UNKNOWN)
381 mode = FQDN;
382
383 if (mode == WRU) {
384 if (ep - buf > 12 && buf[12] == ep - buf - 13)
385 cp = buf + 4;
386 else
387 cp = ep + 1; /*truncated*/
388 modename = "icmp6: who-are-you reply";
389 } else if (mode == FQDN) {
390 cp = buf + 13;
391 modename = "icmp6: FQDN reply";
392 }
393 if (icmp6len > ep - (u_char *)dp) {
394 printf("[|%s]", modename);
395 break;
396 }
397 printf("%s", modename);
398 printf("(\""); /*)*/
399 for (; cp < ep; cp++)
400 printf((isprint(*cp) ? "%c" : "\\%03o"), *cp);
401 printf("\"");
402 if (vflag) {
403 printf(",%s", mode == FQDN ? "FQDN" : "WRU");
404 if (mode == FQDN) {
405 long ttl;
406 ttl = (long)ntohl(*(u_long *)&buf[8]);
407 if (dp->icmp6_code == 1)
408 printf(",TTL=unknown");
409 else if (ttl < 0)
410 printf(",TTL=%ld:invalid", ttl);
411 else
412 printf(",TTL=%ld", ttl);
413 if (buf[12] != ep - buf - 13) {
414 (void)printf(",invalid namelen:%d/%u",
415 buf[12],
416 (unsigned int)(ep - buf - 13));
417 }
418 }
419 }
420 /*(*/
421 printf(")");
422 break;
423 }
424 #endif /*ICMP6_WRUREPLY*/
425 default:
426 printf("icmp6: type-#%d", dp->icmp6_type);
427 break;
428 }
429 return;
430 trunc:
431 fputs("[|icmp6]", stdout);
432 #if 0
433 #undef TCHECK
434 #endif
435 }
436
437 void
438 icmp6_opt_print(register const u_char *bp, int resid)
439 {
440 register const struct nd_opt_hdr *op;
441 register const struct nd_opt_hdr *opl; /* why there's no struct? */
442 register const struct nd_opt_prefix_info *opp;
443 register const struct icmp6_opts_redirect *opr;
444 register const struct nd_opt_mtu *opm;
445 register const u_char *ep;
446 int opts_len;
447 #if 0
448 register const struct ip6_hdr *ip;
449 register const char *str;
450 register const struct ip6_hdr *oip;
451 register const struct udphdr *ouh;
452 register int hlen, dport;
453 char buf[256];
454 #endif
455
456 #if 0
457 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
458 #endif
459 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
460
461 op = (struct nd_opt_hdr *)bp;
462 #if 0
463 ip = (struct ip6_hdr *)bp2;
464 oip = &dp->icmp6_ip6;
465 str = buf;
466 #endif
467 /* 'ep' points to the end of avaible data. */
468 ep = snapend;
469
470 ECHECK(op->nd_opt_len);
471 if (resid <= 0)
472 return;
473 switch(op->nd_opt_type) {
474 case ND_OPT_SOURCE_LINKADDR:
475 opl = (struct nd_opt_hdr *)op;
476 #if 1
477 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
478 goto trunc;
479 #else
480 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
481 #endif
482 printf("(src lladdr: %s", /*)*/
483 etheraddr_string((u_char *)(opl + 1)));
484 if (opl->nd_opt_len != 1)
485 printf("!");
486 /*(*/
487 printf(")");
488 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
489 resid - (op->nd_opt_len << 3));
490 break;
491 case ND_OPT_TARGET_LINKADDR:
492 opl = (struct nd_opt_hdr *)op;
493 #if 1
494 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
495 goto trunc;
496 #else
497 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
498 #endif
499 printf("(tgt lladdr: %s", /*)*/
500 etheraddr_string((u_char *)(opl + 1)));
501 if (opl->nd_opt_len != 1)
502 printf("!");
503 /*(*/
504 printf(")");
505 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
506 resid - (op->nd_opt_len << 3));
507 break;
508 case ND_OPT_PREFIX_INFORMATION:
509 opp = (struct nd_opt_prefix_info *)op;
510 TCHECK(opp->nd_opt_pi_prefix);
511 printf("(prefix info: "); /*)*/
512 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
513 printf("L");
514 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
515 printf("A");
516 if (opp->nd_opt_pi_flags_reserved)
517 printf(" ");
518 printf("valid_ltime=");
519 if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U)
520 printf("infinity");
521 else {
522 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time));
523 }
524 printf(", ");
525 printf("preffered_ltime=");
526 if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U)
527 printf("infinity");
528 else {
529 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time));
530 }
531 printf(", ");
532 printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix),
533 opp->nd_opt_pi_prefix_len);
534 if (opp->nd_opt_pi_len != 4)
535 printf("!");
536 /*(*/
537 printf(")");
538 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
539 resid - (op->nd_opt_len << 3));
540 break;
541 case ND_OPT_REDIRECTED_HEADER:
542 opr = (struct icmp6_opts_redirect *)op;
543 printf("(redirect)");
544 /* xxx */
545 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
546 resid - (op->nd_opt_len << 3));
547 break;
548 case ND_OPT_MTU:
549 opm = (struct nd_opt_mtu *)op;
550 TCHECK(opm->nd_opt_mtu_mtu);
551 printf("(mtu: "); /*)*/
552 printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
553 if (opm->nd_opt_mtu_len != 1)
554 printf("!");
555 printf(")");
556 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
557 resid - (op->nd_opt_len << 3));
558 break;
559 default:
560 opts_len = op->nd_opt_len;
561 printf("(unknwon opt_type=%d, opt_len=%d)",
562 op->nd_opt_type, opts_len);
563 if (opts_len == 0)
564 opts_len = 1; /* XXX */
565 icmp6_opt_print((const u_char *)op + (opts_len << 3),
566 resid - (opts_len << 3));
567 break;
568 }
569 return;
570 trunc:
571 fputs("[ndp opt]", stdout);
572 return;
573 #if 0
574 #undef TCHECK
575 #endif
576 #undef ECHECK
577 }
578
579 void
580 mld6_print(register const u_char *bp)
581 {
582 register struct mld6_hdr *mp = (struct mld6_hdr *)bp;
583 register const u_char *ep;
584
585 /* 'ep' points to the end of avaible data. */
586 ep = snapend;
587
588 if ((u_char *)mp + sizeof(*mp) > ep)
589 return;
590
591 printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay));
592 printf("addr: %s", ip6addr_string(&mp->mld6_addr));
593
594 return;
595 }
596 #endif /* INET6 */