dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.sbin / snoop / snoop_ip.c
blob97b18ef20d8f033e5eb7056fb886a41674fef088
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
27 #include <stdio.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/time.h>
34 #include <sys/stropts.h>
35 #include <sys/socket.h>
36 #include <net/if.h>
37 #include <netinet/in_systm.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip6.h>
41 #include <netinet/ip_icmp.h>
42 #include <netinet/icmp6.h>
43 #include <netinet/if_ether.h>
44 #include <inet/ip.h>
45 #include <inet/ip6.h>
46 #include <arpa/inet.h>
47 #include <netdb.h>
49 #include "snoop.h"
53 * IPv6 extension header masks. These are used by the print_ipv6_extensions()
54 * function to return information to the caller about which extension headers
55 * were processed. This can be useful if the caller wants to know if the
56 * packet is an IPv6 fragment, for example.
58 #define SNOOP_HOPOPTS 0x01U
59 #define SNOOP_ROUTING 0x02U
60 #define SNOOP_DSTOPTS 0x04U
61 #define SNOOP_FRAGMENT 0x08U
62 #define SNOOP_AH 0x10U
63 #define SNOOP_ESP 0x20U
64 #define SNOOP_IPV6 0x40U
66 static void prt_routing_hdr(int, const struct ip6_rthdr *);
67 static void prt_fragment_hdr(int, const struct ip6_frag *);
68 static void prt_hbh_options(int, const struct ip6_hbh *);
69 static void prt_dest_options(int, const struct ip6_dest *);
70 static void print_route(const uchar_t *);
71 static void print_ipoptions(const uchar_t *, int);
73 /* Keep track of how many nested IP headers we have. */
74 unsigned int encap_levels;
75 unsigned int total_encap_levels = 1;
77 int
78 interpret_ip(int flags, const struct ip *ip, int fraglen)
80 uchar_t *data;
81 char buff[24];
82 boolean_t isfrag = B_FALSE;
83 boolean_t morefrag;
84 uint16_t fragoffset;
85 int hdrlen;
86 uint16_t iplen, uitmp;
88 if (ip->ip_v == IPV6_VERSION) {
89 iplen = interpret_ipv6(flags, (ip6_t *)ip, fraglen);
90 return (iplen);
93 if (encap_levels == 0)
94 total_encap_levels = 0;
95 encap_levels++;
96 total_encap_levels++;
98 hdrlen = ip->ip_hl * 4;
99 data = ((uchar_t *)ip) + hdrlen;
100 iplen = ntohs(ip->ip_len) - hdrlen;
101 fraglen -= hdrlen;
102 if (fraglen > iplen)
103 fraglen = iplen;
104 if (fraglen < 0) {
105 (void) snprintf(get_sum_line(), MAXLINE,
106 "IP truncated: header missing %d bytes", -fraglen);
107 encap_levels--;
108 return (fraglen + iplen);
111 * We flag this as a fragment if the more fragments bit is set, or
112 * if the fragment offset is non-zero.
114 morefrag = (ntohs(ip->ip_off) & IP_MF) == 0 ? B_FALSE : B_TRUE;
115 fragoffset = (ntohs(ip->ip_off) & 0x1FFF) * 8;
116 if (morefrag || fragoffset != 0)
117 isfrag = B_TRUE;
119 src_name = addrtoname(AF_INET, &ip->ip_src);
120 dst_name = addrtoname(AF_INET, &ip->ip_dst);
122 if (flags & F_SUM) {
123 if (isfrag) {
124 (void) snprintf(get_sum_line(), MAXLINE,
125 "%s IP fragment ID=%d Offset=%-4d MF=%d TOS=0x%x "
126 "TTL=%d",
127 getproto(ip->ip_p),
128 ntohs(ip->ip_id),
129 fragoffset,
130 morefrag,
131 ip->ip_tos,
132 ip->ip_ttl);
133 } else {
134 (void) strlcpy(buff, inet_ntoa(ip->ip_dst),
135 sizeof (buff));
136 uitmp = ntohs(ip->ip_len);
137 (void) snprintf(get_sum_line(), MAXLINE,
138 "IP D=%s S=%s LEN=%u%s, ID=%d, TOS=0x%x, TTL=%d",
139 buff,
140 inet_ntoa(ip->ip_src),
141 uitmp,
142 iplen > fraglen ? "?" : "",
143 ntohs(ip->ip_id),
144 ip->ip_tos,
145 ip->ip_ttl);
149 if (flags & F_DTAIL) {
150 show_header("IP: ", "IP Header", iplen);
151 show_space();
152 (void) snprintf(get_line(0, 0), get_line_remain(),
153 "Version = %d", ip->ip_v);
154 (void) snprintf(get_line(0, 0), get_line_remain(),
155 "Header length = %d bytes", hdrlen);
156 (void) snprintf(get_line(0, 0), get_line_remain(),
157 "Type of service = 0x%02x", ip->ip_tos);
158 (void) snprintf(get_line(0, 0), get_line_remain(),
159 " xxx. .... = %d (precedence)",
160 ip->ip_tos >> 5);
161 (void) snprintf(get_line(0, 0), get_line_remain(),
162 " %s", getflag(ip->ip_tos, IPTOS_LOWDELAY,
163 "low delay", "normal delay"));
164 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
165 getflag(ip->ip_tos, IPTOS_THROUGHPUT,
166 "high throughput", "normal throughput"));
167 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
168 getflag(ip->ip_tos, IPTOS_RELIABILITY,
169 "high reliability", "normal reliability"));
170 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
171 getflag(ip->ip_tos, IPTOS_ECT,
172 "ECN capable transport", "not ECN capable transport"));
173 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
174 getflag(ip->ip_tos, IPTOS_CE,
175 "ECN congestion experienced",
176 "no ECN congestion experienced"));
177 /* warning: ip_len is signed in netinet/ip.h */
178 uitmp = ntohs(ip->ip_len);
179 (void) snprintf(get_line(0, 0), get_line_remain(),
180 "Total length = %u bytes%s", uitmp,
181 iplen > fraglen ? " -- truncated" : "");
182 (void) snprintf(get_line(0, 0), get_line_remain(),
183 "Identification = %d", ntohs(ip->ip_id));
184 /* warning: ip_off is signed in netinet/ip.h */
185 uitmp = ntohs(ip->ip_off);
186 (void) snprintf(get_line(0, 0), get_line_remain(),
187 "Flags = 0x%x", uitmp >> 12);
188 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
189 getflag(uitmp >> 8, IP_DF >> 8,
190 "do not fragment", "may fragment"));
191 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
192 getflag(uitmp >> 8, IP_MF >> 8,
193 "more fragments", "last fragment"));
194 (void) snprintf(get_line(0, 0), get_line_remain(),
195 "Fragment offset = %u bytes",
196 fragoffset);
197 (void) snprintf(get_line(0, 0), get_line_remain(),
198 "Time to live = %d seconds/hops",
199 ip->ip_ttl);
200 (void) snprintf(get_line(0, 0), get_line_remain(),
201 "Protocol = %d (%s)", ip->ip_p,
202 getproto(ip->ip_p));
204 * XXX need to compute checksum and print whether it's correct
206 (void) snprintf(get_line(0, 0), get_line_remain(),
207 "Header checksum = %04x",
208 ntohs(ip->ip_sum));
209 (void) snprintf(get_line(0, 0), get_line_remain(),
210 "Source address = %s, %s",
211 inet_ntoa(ip->ip_src), addrtoname(AF_INET, &ip->ip_src));
212 (void) snprintf(get_line(0, 0), get_line_remain(),
213 "Destination address = %s, %s",
214 inet_ntoa(ip->ip_dst), addrtoname(AF_INET, &ip->ip_dst));
216 /* Print IP options - if any */
218 print_ipoptions((const uchar_t *)(ip + 1),
219 hdrlen - sizeof (struct ip));
220 show_space();
224 * If we are in detail mode, and this is not the first fragment of
225 * a fragmented packet, print out a little line stating this.
226 * Otherwise, go to the next protocol layer only if this is not a
227 * fragment, or we are in detail mode and this is the first fragment
228 * of a fragmented packet.
230 if (flags & F_DTAIL && fragoffset != 0) {
231 (void) snprintf(get_detail_line(0, 0), MAXLINE,
232 "%s: [%d byte(s) of data, continuation of IP ident=%d]",
233 getproto(ip->ip_p),
234 iplen,
235 ntohs(ip->ip_id));
236 } else if (!isfrag || (flags & F_DTAIL) && isfrag && fragoffset == 0) {
237 /* go to the next protocol layer */
239 if (fraglen > 0) {
240 switch (ip->ip_p) {
241 case IPPROTO_IP:
242 break;
243 case IPPROTO_ENCAP:
244 (void) interpret_ip(flags,
245 /* LINTED: alignment */
246 (const struct ip *)data, fraglen);
247 break;
248 case IPPROTO_ICMP:
249 (void) interpret_icmp(flags,
250 /* LINTED: alignment */
251 (struct icmp *)data, iplen, fraglen);
252 break;
253 case IPPROTO_IGMP:
254 interpret_igmp(flags, data, iplen, fraglen);
255 break;
256 case IPPROTO_GGP:
257 break;
258 case IPPROTO_TCP:
259 (void) interpret_tcp(flags,
260 (struct tcphdr *)data, iplen, fraglen);
261 break;
263 case IPPROTO_ESP:
264 (void) interpret_esp(flags, data, iplen,
265 fraglen);
266 break;
267 case IPPROTO_AH:
268 (void) interpret_ah(flags, data, iplen,
269 fraglen);
270 break;
272 case IPPROTO_OSPF:
273 interpret_ospf(flags, data, iplen, fraglen);
274 break;
276 case IPPROTO_EGP:
277 case IPPROTO_PUP:
278 break;
279 case IPPROTO_UDP:
280 (void) interpret_udp(flags,
281 (struct udphdr *)data, iplen, fraglen);
282 break;
284 case IPPROTO_IDP:
285 case IPPROTO_HELLO:
286 case IPPROTO_ND:
287 case IPPROTO_RAW:
288 break;
289 case IPPROTO_IPV6: /* IPV6 encap */
290 /* LINTED: alignment */
291 (void) interpret_ipv6(flags, (ip6_t *)data,
292 iplen);
293 break;
294 case IPPROTO_SCTP:
295 (void) interpret_sctp(flags,
296 (struct sctp_hdr *)data, iplen, fraglen);
297 break;
302 encap_levels--;
303 return (iplen);
307 interpret_ipv6(int flags, const ip6_t *ip6h, int fraglen)
309 uint8_t *data;
310 int hdrlen, iplen;
311 int version, flow, class;
312 uchar_t proto;
313 boolean_t isfrag = B_FALSE;
314 uint8_t extmask;
316 * The print_srcname and print_dstname strings are the hostname
317 * parts of the verbose IPv6 header output, including the comma
318 * and the space after the litteral address strings.
320 char print_srcname[MAXHOSTNAMELEN + 2];
321 char print_dstname[MAXHOSTNAMELEN + 2];
322 char src_addrstr[INET6_ADDRSTRLEN];
323 char dst_addrstr[INET6_ADDRSTRLEN];
325 iplen = ntohs(ip6h->ip6_plen);
326 hdrlen = IPV6_HDR_LEN;
327 fraglen -= hdrlen;
328 if (fraglen < 0)
329 return (fraglen + hdrlen);
330 data = ((uint8_t *)ip6h) + hdrlen;
332 proto = ip6h->ip6_nxt;
334 src_name = addrtoname(AF_INET6, &ip6h->ip6_src);
335 dst_name = addrtoname(AF_INET6, &ip6h->ip6_dst);
338 * Use endian-aware masks to extract traffic class and
339 * flowinfo. Also, flowinfo is now 20 bits and class 8
340 * rather than 24 and 4.
342 class = ntohl((ip6h->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20);
343 flow = ntohl(ip6h->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL);
346 * NOTE: the F_SUM and F_DTAIL flags are mutually exclusive,
347 * so the code within the first part of the following if statement
348 * will not affect the detailed printing of the packet.
350 if (flags & F_SUM) {
351 (void) snprintf(get_sum_line(), MAXLINE,
352 "IPv6 S=%s D=%s LEN=%d HOPS=%d CLASS=0x%x FLOW=0x%x",
353 src_name, dst_name, iplen, ip6h->ip6_hops, class, flow);
354 } else if (flags & F_DTAIL) {
356 (void) inet_ntop(AF_INET6, &ip6h->ip6_src, src_addrstr,
357 INET6_ADDRSTRLEN);
358 (void) inet_ntop(AF_INET6, &ip6h->ip6_dst, dst_addrstr,
359 INET6_ADDRSTRLEN);
361 version = ntohl(ip6h->ip6_vcf) >> 28;
363 if (strcmp(src_name, src_addrstr) == 0) {
364 print_srcname[0] = '\0';
365 } else {
366 snprintf(print_srcname, sizeof (print_srcname),
367 ", %s", src_name);
370 if (strcmp(dst_name, dst_addrstr) == 0) {
371 print_dstname[0] = '\0';
372 } else {
373 snprintf(print_dstname, sizeof (print_dstname),
374 ", %s", dst_name);
377 show_header("IPv6: ", "IPv6 Header", iplen);
378 show_space();
380 (void) snprintf(get_line(0, 0), get_line_remain(),
381 "Version = %d", version);
382 (void) snprintf(get_line(0, 0), get_line_remain(),
383 "Traffic Class = %d", class);
384 (void) snprintf(get_line(0, 0), get_line_remain(),
385 "Flow label = 0x%x", flow);
386 (void) snprintf(get_line(0, 0), get_line_remain(),
387 "Payload length = %d", iplen);
388 (void) snprintf(get_line(0, 0), get_line_remain(),
389 "Next Header = %d (%s)", proto,
390 getproto(proto));
391 (void) snprintf(get_line(0, 0), get_line_remain(),
392 "Hop Limit = %d", ip6h->ip6_hops);
393 (void) snprintf(get_line(0, 0), get_line_remain(),
394 "Source address = %s%s", src_addrstr, print_srcname);
395 (void) snprintf(get_line(0, 0), get_line_remain(),
396 "Destination address = %s%s", dst_addrstr, print_dstname);
398 show_space();
402 * Print IPv6 Extension Headers, or skip them in the summary case.
403 * Set isfrag to true if one of the extension headers encounterred
404 * was a fragment header.
406 if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS ||
407 proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) {
408 extmask = print_ipv6_extensions(flags, &data, &proto, &iplen,
409 &fraglen);
410 if ((extmask & SNOOP_FRAGMENT) != 0) {
411 isfrag = B_TRUE;
416 * We only want to print upper layer information if this is not
417 * a fragment, or if we're printing in detail. Note that the
418 * proto variable will be set to IPPROTO_NONE if this is a fragment
419 * with a non-zero fragment offset.
421 if (!isfrag || flags & F_DTAIL) {
422 /* go to the next protocol layer */
424 switch (proto) {
425 case IPPROTO_IP:
426 break;
427 case IPPROTO_ENCAP:
428 /* LINTED: alignment */
429 (void) interpret_ip(flags, (const struct ip *)data,
430 fraglen);
431 break;
432 case IPPROTO_ICMPV6:
433 /* LINTED: alignment */
434 (void) interpret_icmpv6(flags, (icmp6_t *)data, iplen,
435 fraglen);
436 break;
437 case IPPROTO_IGMP:
438 interpret_igmp(flags, data, iplen, fraglen);
439 break;
440 case IPPROTO_GGP:
441 break;
442 case IPPROTO_TCP:
443 (void) interpret_tcp(flags, (struct tcphdr *)data,
444 iplen, fraglen);
445 break;
446 case IPPROTO_ESP:
447 (void) interpret_esp(flags, data, iplen, fraglen);
448 break;
449 case IPPROTO_AH:
450 (void) interpret_ah(flags, data, iplen, fraglen);
451 break;
452 case IPPROTO_EGP:
453 case IPPROTO_PUP:
454 break;
455 case IPPROTO_UDP:
456 (void) interpret_udp(flags, (struct udphdr *)data,
457 iplen, fraglen);
458 break;
459 case IPPROTO_IDP:
460 case IPPROTO_HELLO:
461 case IPPROTO_ND:
462 case IPPROTO_RAW:
463 break;
464 case IPPROTO_IPV6:
465 /* LINTED: alignment */
466 (void) interpret_ipv6(flags, (const ip6_t *)data,
467 iplen);
468 break;
469 case IPPROTO_SCTP:
470 (void) interpret_sctp(flags, (struct sctp_hdr *)data,
471 iplen, fraglen);
472 break;
473 case IPPROTO_OSPF:
474 interpret_ospf6(flags, data, iplen, fraglen);
475 break;
479 return (iplen);
483 * ip_ext: data including the extension header.
484 * iplen: length of the data remaining in the packet.
485 * Returns a mask of IPv6 extension headers it processed.
487 uint8_t
488 print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen,
489 int *fraglen)
491 uint8_t *data_ptr;
492 uchar_t proto = *next;
493 boolean_t is_extension_header;
494 struct ip6_hbh *ipv6ext_hbh;
495 struct ip6_dest *ipv6ext_dest;
496 struct ip6_rthdr *ipv6ext_rthdr;
497 struct ip6_frag *ipv6ext_frag;
498 uint32_t exthdrlen;
499 uint8_t extmask = 0;
501 if ((hdr == NULL) || (*hdr == NULL) || (next == NULL) || (iplen == 0))
502 return (0);
504 data_ptr = *hdr;
505 is_extension_header = B_TRUE;
506 while (is_extension_header) {
509 * There must be at least enough data left to read the
510 * next header and header length fields from the next
511 * header.
513 if (*fraglen < 2) {
514 return (extmask);
517 switch (proto) {
518 case IPPROTO_HOPOPTS:
519 ipv6ext_hbh = (struct ip6_hbh *)data_ptr;
520 exthdrlen = 8 + ipv6ext_hbh->ip6h_len * 8;
521 if (*fraglen <= exthdrlen) {
522 return (extmask);
524 prt_hbh_options(flags, ipv6ext_hbh);
525 extmask |= SNOOP_HOPOPTS;
526 proto = ipv6ext_hbh->ip6h_nxt;
527 break;
528 case IPPROTO_DSTOPTS:
529 ipv6ext_dest = (struct ip6_dest *)data_ptr;
530 exthdrlen = 8 + ipv6ext_dest->ip6d_len * 8;
531 if (*fraglen <= exthdrlen) {
532 return (extmask);
534 prt_dest_options(flags, ipv6ext_dest);
535 extmask |= SNOOP_DSTOPTS;
536 proto = ipv6ext_dest->ip6d_nxt;
537 break;
538 case IPPROTO_ROUTING:
539 ipv6ext_rthdr = (struct ip6_rthdr *)data_ptr;
540 exthdrlen = 8 + ipv6ext_rthdr->ip6r_len * 8;
541 if (*fraglen <= exthdrlen) {
542 return (extmask);
544 prt_routing_hdr(flags, ipv6ext_rthdr);
545 extmask |= SNOOP_ROUTING;
546 proto = ipv6ext_rthdr->ip6r_nxt;
547 break;
548 case IPPROTO_FRAGMENT:
549 /* LINTED: alignment */
550 ipv6ext_frag = (struct ip6_frag *)data_ptr;
551 exthdrlen = sizeof (struct ip6_frag);
552 if (*fraglen <= exthdrlen) {
553 return (extmask);
555 prt_fragment_hdr(flags, ipv6ext_frag);
556 extmask |= SNOOP_FRAGMENT;
558 * If this is not the first fragment, forget about
559 * the rest of the packet, snoop decoding is
560 * stateless.
562 if ((ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK) != 0)
563 proto = IPPROTO_NONE;
564 else
565 proto = ipv6ext_frag->ip6f_nxt;
566 break;
567 default:
568 is_extension_header = B_FALSE;
569 break;
572 if (is_extension_header) {
573 *iplen -= exthdrlen;
574 *fraglen -= exthdrlen;
575 data_ptr += exthdrlen;
579 *next = proto;
580 *hdr = data_ptr;
581 return (extmask);
584 static void
585 print_ipoptions(const uchar_t *opt, int optlen)
587 int len;
588 int remain;
589 char *line;
590 const char *truncstr;
592 if (optlen <= 0) {
593 (void) snprintf(get_line(0, 0), get_line_remain(),
594 "No options");
595 return;
598 (void) snprintf(get_line(0, 0), get_line_remain(),
599 "Options: (%d bytes)", optlen);
601 while (optlen > 0) {
602 line = get_line(0, 0);
603 remain = get_line_remain();
604 len = opt[1];
605 truncstr = len > optlen ? "?" : "";
606 switch (opt[0]) {
607 case IPOPT_EOL:
608 (void) strlcpy(line, " - End of option list", remain);
609 return;
610 case IPOPT_NOP:
611 (void) strlcpy(line, " - No op", remain);
612 len = 1;
613 break;
614 case IPOPT_RR:
615 (void) snprintf(line, remain,
616 " - Record route (%d bytes%s)", len, truncstr);
617 print_route(opt);
618 break;
619 case IPOPT_TS:
620 (void) snprintf(line, remain,
621 " - Time stamp (%d bytes%s)", len, truncstr);
622 break;
623 case IPOPT_SECURITY:
624 (void) snprintf(line, remain, " - RIPSO (%d bytes%s)",
625 len, truncstr);
626 break;
627 case IPOPT_LSRR:
628 (void) snprintf(line, remain,
629 " - Loose source route (%d bytes%s)", len,
630 truncstr);
631 print_route(opt);
632 break;
633 case IPOPT_SATID:
634 (void) snprintf(line, remain,
635 " - SATNET Stream id (%d bytes%s)",
636 len, truncstr);
637 break;
638 case IPOPT_SSRR:
639 (void) snprintf(line, remain,
640 " - Strict source route, (%d bytes%s)", len,
641 truncstr);
642 print_route(opt);
643 break;
644 default:
645 (void) snprintf(line, remain,
646 " - Option %d (unknown - %d bytes%s) %s",
647 opt[0], len, truncstr,
648 tohex((char *)&opt[2], len - 2));
649 break;
651 if (len <= 0) {
652 (void) snprintf(line, remain,
653 " - Incomplete option len %d", len);
654 break;
656 opt += len;
657 optlen -= len;
661 static void
662 print_route(const uchar_t *opt)
664 int len, pointer, remain;
665 struct in_addr addr;
666 char *line;
668 len = opt[1];
669 pointer = opt[2];
671 (void) snprintf(get_line(0, 0), get_line_remain(),
672 " Pointer = %d", pointer);
674 pointer -= IPOPT_MINOFF;
675 opt += (IPOPT_OFFSET + 1);
676 len -= (IPOPT_OFFSET + 1);
678 while (len > 0) {
679 line = get_line(0, 0);
680 remain = get_line_remain();
681 memcpy((char *)&addr, opt, sizeof (addr));
682 if (addr.s_addr == INADDR_ANY)
683 (void) strlcpy(line, " -", remain);
684 else
685 (void) snprintf(line, remain, " %s",
686 addrtoname(AF_INET, &addr));
687 if (pointer == 0)
688 (void) strlcat(line, " <-- (current)", remain);
690 opt += sizeof (addr);
691 len -= sizeof (addr);
692 pointer -= sizeof (addr);
696 char *
697 getproto(int p)
699 switch (p) {
700 case IPPROTO_HOPOPTS: return ("IPv6-HopOpts");
701 case IPPROTO_IPV6: return ("IPv6");
702 case IPPROTO_ROUTING: return ("IPv6-Route");
703 case IPPROTO_FRAGMENT: return ("IPv6-Frag");
704 case IPPROTO_RSVP: return ("RSVP");
705 case IPPROTO_ENCAP: return ("IP-in-IP");
706 case IPPROTO_AH: return ("AH");
707 case IPPROTO_ESP: return ("ESP");
708 case IPPROTO_ICMP: return ("ICMP");
709 case IPPROTO_ICMPV6: return ("ICMPv6");
710 case IPPROTO_DSTOPTS: return ("IPv6-DstOpts");
711 case IPPROTO_IGMP: return ("IGMP");
712 case IPPROTO_GGP: return ("GGP");
713 case IPPROTO_TCP: return ("TCP");
714 case IPPROTO_EGP: return ("EGP");
715 case IPPROTO_PUP: return ("PUP");
716 case IPPROTO_UDP: return ("UDP");
717 case IPPROTO_IDP: return ("IDP");
718 case IPPROTO_HELLO: return ("HELLO");
719 case IPPROTO_ND: return ("ND");
720 case IPPROTO_EON: return ("EON");
721 case IPPROTO_RAW: return ("RAW");
722 case IPPROTO_OSPF: return ("OSPF");
723 default: return ("");
727 static void
728 prt_routing_hdr(int flags, const struct ip6_rthdr *ipv6ext_rthdr)
730 uint8_t nxt_hdr;
731 uint8_t type;
732 uint32_t len;
733 uint8_t segleft;
734 uint32_t numaddrs;
735 int i;
736 struct ip6_rthdr0 *ipv6ext_rthdr0;
737 struct in6_addr *addrs;
738 char addr[INET6_ADDRSTRLEN];
740 /* in summary mode, we don't do anything. */
741 if (flags & F_SUM) {
742 return;
745 nxt_hdr = ipv6ext_rthdr->ip6r_nxt;
746 type = ipv6ext_rthdr->ip6r_type;
747 len = 8 * (ipv6ext_rthdr->ip6r_len + 1);
748 segleft = ipv6ext_rthdr->ip6r_segleft;
750 show_header("IPv6-Route: ", "IPv6 Routing Header", 0);
751 show_space();
753 (void) snprintf(get_line(0, 0), get_line_remain(),
754 "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr));
755 (void) snprintf(get_line(0, 0), get_line_remain(),
756 "Header length = %d", len);
757 (void) snprintf(get_line(0, 0), get_line_remain(),
758 "Routing type = %d", type);
759 (void) snprintf(get_line(0, 0), get_line_remain(),
760 "Segments left = %d", segleft);
762 if (type == IPV6_RTHDR_TYPE_0) {
764 * XXX This loop will print all addresses in the routing header,
765 * XXX not just the segments left.
766 * XXX (The header length field is twice the number of
767 * XXX addresses)
768 * XXX At some future time, we may want to change this
769 * XXX to differentiate between the hops yet to do
770 * XXX and the hops already taken.
772 /* LINTED: alignment */
773 ipv6ext_rthdr0 = (struct ip6_rthdr0 *)ipv6ext_rthdr;
774 numaddrs = ipv6ext_rthdr0->ip6r0_len / 2;
775 addrs = (struct in6_addr *)(ipv6ext_rthdr0 + 1);
776 for (i = 0; i < numaddrs; i++) {
777 (void) inet_ntop(AF_INET6, &addrs[i], addr,
778 INET6_ADDRSTRLEN);
779 (void) snprintf(get_line(0, 0), get_line_remain(),
780 "address[%d]=%s", i, addr);
784 show_space();
787 static void
788 prt_fragment_hdr(int flags, const struct ip6_frag *ipv6ext_frag)
790 boolean_t morefrag;
791 uint16_t fragoffset;
792 uint8_t nxt_hdr;
793 uint32_t fragident;
795 /* extract the various fields from the fragment header */
796 nxt_hdr = ipv6ext_frag->ip6f_nxt;
797 morefrag = (ipv6ext_frag->ip6f_offlg & IP6F_MORE_FRAG) == 0
798 ? B_FALSE : B_TRUE;
799 fragoffset = ntohs(ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK);
800 fragident = ntohl(ipv6ext_frag->ip6f_ident);
802 if (flags & F_SUM) {
803 (void) snprintf(get_sum_line(), MAXLINE,
804 "IPv6 fragment ID=%u Offset=%-4d MF=%d",
805 fragident,
806 fragoffset,
807 morefrag);
808 } else { /* F_DTAIL */
809 show_header("IPv6-Frag: ", "IPv6 Fragment Header", 0);
810 show_space();
812 (void) snprintf(get_line(0, 0), get_line_remain(),
813 "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr));
814 (void) snprintf(get_line(0, 0), get_line_remain(),
815 "Fragment Offset = %d", fragoffset);
816 (void) snprintf(get_line(0, 0), get_line_remain(),
817 "More Fragments Flag = %s", morefrag ? "true" : "false");
818 (void) snprintf(get_line(0, 0), get_line_remain(),
819 "Identification = %u", fragident);
821 show_space();
825 static void
826 prt_hbh_options(int flags, const struct ip6_hbh *ipv6ext_hbh)
828 const uint8_t *data, *ndata;
829 uint32_t len;
830 uint8_t op_type;
831 uint8_t op_len;
832 uint8_t nxt_hdr;
834 /* in summary mode, we don't do anything. */
835 if (flags & F_SUM) {
836 return;
839 show_header("IPv6-HopOpts: ", "IPv6 Hop-by-Hop Options Header", 0);
840 show_space();
843 * Store the lengh of this ext hdr in bytes. The caller has
844 * ensured that there is at least len bytes of data left.
846 len = ipv6ext_hbh->ip6h_len * 8 + 8;
848 ndata = (const uint8_t *)ipv6ext_hbh + 2;
849 len -= 2;
851 nxt_hdr = ipv6ext_hbh->ip6h_nxt;
852 (void) snprintf(get_line(0, 0), get_line_remain(),
853 "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr));
855 while (len > 0) {
856 data = ndata;
857 GETINT8(op_type, data);
858 /* This is the only one-octet IPv6 option */
859 if (op_type == IP6OPT_PAD1) {
860 (void) snprintf(get_line(0, 0), get_line_remain(),
861 "pad1 option ");
862 len--;
863 ndata = data;
864 continue;
866 GETINT8(op_len, data);
867 if (len < 2 || op_len + 2 > len) {
868 (void) snprintf(get_line(0, 0), get_line_remain(),
869 "Error: option %u truncated (%u + 2 > %u)",
870 op_type, op_len, len);
871 op_len = len - 2;
873 * Continue processing the malformed option so that we
874 * can display as much as possible.
878 /* advance pointers to the next option */
879 len -= op_len + 2;
880 ndata = data + op_len;
882 /* process this option */
883 switch (op_type) {
884 case IP6OPT_PADN:
885 (void) snprintf(get_line(0, 0), get_line_remain(),
886 "padN option len = %u", op_len);
887 break;
888 case IP6OPT_JUMBO: {
889 uint32_t payload_len;
891 (void) snprintf(get_line(0, 0), get_line_remain(),
892 "Jumbo Payload Option len = %u bytes%s", op_len,
893 op_len == sizeof (uint32_t) ? "" : "?");
894 if (op_len == sizeof (uint32_t)) {
895 GETINT32(payload_len, data);
896 (void) snprintf(get_line(0, 0),
897 get_line_remain(),
898 "Jumbo Payload Length = %u bytes",
899 payload_len);
901 break;
903 case IP6OPT_ROUTER_ALERT: {
904 uint16_t value;
905 const char *label[] = {"MLD", "RSVP", "AN"};
907 (void) snprintf(get_line(0, 0), get_line_remain(),
908 "Router Alert Option len = %u bytes%s", op_len,
909 op_len == sizeof (uint16_t) ? "" : "?");
910 if (op_len == sizeof (uint16_t)) {
911 GETINT16(value, data);
912 (void) snprintf(get_line(0, 0),
913 get_line_remain(),
914 "Alert Type = %d (%s)", value,
915 value < sizeof (label) / sizeof (label[0]) ?
916 label[value] : "???");
918 break;
920 default:
921 (void) snprintf(get_line(0, 0), get_line_remain(),
922 "Option type = %u, len = %u", op_type, op_len);
923 break;
927 show_space();
930 static void
931 prt_dest_options(int flags, const struct ip6_dest *ipv6ext_dest)
933 const uint8_t *data, *ndata;
934 uint32_t len;
935 uint8_t op_type;
936 uint32_t op_len;
937 uint8_t nxt_hdr;
938 uint8_t value;
940 /* in summary mode, we don't do anything. */
941 if (flags & F_SUM) {
942 return;
945 show_header("IPv6-DstOpts: ", "IPv6 Destination Options Header", 0);
946 show_space();
949 * Store the length of this ext hdr in bytes. The caller has
950 * ensured that there is at least len bytes of data left.
952 len = ipv6ext_dest->ip6d_len * 8 + 8;
954 ndata = (const uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */
955 len -= 2;
957 nxt_hdr = ipv6ext_dest->ip6d_nxt;
958 (void) snprintf(get_line(0, 0), get_line_remain(),
959 "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr));
961 while (len > 0) {
962 data = ndata;
963 GETINT8(op_type, data);
964 if (op_type == IP6OPT_PAD1) {
965 (void) snprintf(get_line(0, 0), get_line_remain(),
966 "pad1 option ");
967 len--;
968 ndata = data;
969 continue;
971 GETINT8(op_len, data);
972 if (len < 2 || op_len + 2 > len) {
973 (void) snprintf(get_line(0, 0), get_line_remain(),
974 "Error: option %u truncated (%u + 2 > %u)",
975 op_type, op_len, len);
976 op_len = len - 2;
978 * Continue processing the malformed option so that we
979 * can display as much as possible.
983 /* advance pointers to the next option */
984 len -= op_len + 2;
985 ndata = data + op_len;
987 /* process this option */
988 switch (op_type) {
989 case IP6OPT_PADN:
990 (void) snprintf(get_line(0, 0), get_line_remain(),
991 "padN option len = %u", op_len);
992 break;
993 case IP6OPT_TUNNEL_LIMIT:
994 GETINT8(value, data);
995 (void) snprintf(get_line(0, 0), get_line_remain(),
996 "tunnel encapsulation limit len = %d, value = %d",
997 op_len, value);
998 break;
999 default:
1000 (void) snprintf(get_line(0, 0), get_line_remain(),
1001 "Option type = %u, len = %u", op_type, op_len);
1002 break;
1006 show_space();