Print this page
dccp: snoop, build system fixes
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ip.c
+++ new/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ip.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 #include <stdio.h>
27 27 #include <string.h>
28 28 #include <fcntl.h>
29 29 #include <string.h>
30 30 #include <sys/types.h>
31 31 #include <sys/time.h>
32 32
33 33 #include <sys/stropts.h>
34 34 #include <sys/socket.h>
35 35 #include <net/if.h>
36 36 #include <netinet/in_systm.h>
37 37 #include <netinet/in.h>
38 38 #include <netinet/ip.h>
39 39 #include <netinet/ip6.h>
40 40 #include <netinet/ip_icmp.h>
41 41 #include <netinet/icmp6.h>
42 42 #include <netinet/if_ether.h>
43 43 #include <inet/ip.h>
44 44 #include <inet/ip6.h>
45 45 #include <arpa/inet.h>
46 46 #include <netdb.h>
47 47 #include <tsol/label.h>
48 48 #include <sys/tsol/tndb.h>
49 49 #include <sys/tsol/label_macro.h>
50 50
51 51 #include "snoop.h"
52 52
53 53
54 54 /*
55 55 * IPv6 extension header masks. These are used by the print_ipv6_extensions()
56 56 * function to return information to the caller about which extension headers
57 57 * were processed. This can be useful if the caller wants to know if the
58 58 * packet is an IPv6 fragment, for example.
59 59 */
60 60 #define SNOOP_HOPOPTS 0x01U
61 61 #define SNOOP_ROUTING 0x02U
62 62 #define SNOOP_DSTOPTS 0x04U
63 63 #define SNOOP_FRAGMENT 0x08U
64 64 #define SNOOP_AH 0x10U
65 65 #define SNOOP_ESP 0x20U
66 66 #define SNOOP_IPV6 0x40U
67 67
68 68 static void prt_routing_hdr(int, const struct ip6_rthdr *);
69 69 static void prt_fragment_hdr(int, const struct ip6_frag *);
70 70 static void prt_hbh_options(int, const struct ip6_hbh *);
71 71 static void prt_dest_options(int, const struct ip6_dest *);
72 72 static void print_route(const uchar_t *);
73 73 static void print_ipoptions(const uchar_t *, int);
74 74 static void print_ripso(const uchar_t *);
75 75 static void print_cipso(const uchar_t *);
76 76
77 77 /* Keep track of how many nested IP headers we have. */
78 78 unsigned int encap_levels;
79 79 unsigned int total_encap_levels = 1;
80 80
81 81 int
82 82 interpret_ip(int flags, const struct ip *ip, int fraglen)
83 83 {
84 84 uchar_t *data;
85 85 char buff[24];
86 86 boolean_t isfrag = B_FALSE;
87 87 boolean_t morefrag;
88 88 uint16_t fragoffset;
89 89 int hdrlen;
90 90 uint16_t iplen, uitmp;
91 91
92 92 if (ip->ip_v == IPV6_VERSION) {
93 93 iplen = interpret_ipv6(flags, (ip6_t *)ip, fraglen);
94 94 return (iplen);
95 95 }
96 96
97 97 if (encap_levels == 0)
98 98 total_encap_levels = 0;
99 99 encap_levels++;
100 100 total_encap_levels++;
101 101
102 102 hdrlen = ip->ip_hl * 4;
103 103 data = ((uchar_t *)ip) + hdrlen;
104 104 iplen = ntohs(ip->ip_len) - hdrlen;
105 105 fraglen -= hdrlen;
106 106 if (fraglen > iplen)
107 107 fraglen = iplen;
108 108 if (fraglen < 0) {
109 109 (void) snprintf(get_sum_line(), MAXLINE,
110 110 "IP truncated: header missing %d bytes", -fraglen);
111 111 encap_levels--;
112 112 return (fraglen + iplen);
113 113 }
114 114 /*
115 115 * We flag this as a fragment if the more fragments bit is set, or
116 116 * if the fragment offset is non-zero.
117 117 */
118 118 morefrag = (ntohs(ip->ip_off) & IP_MF) == 0 ? B_FALSE : B_TRUE;
119 119 fragoffset = (ntohs(ip->ip_off) & 0x1FFF) * 8;
120 120 if (morefrag || fragoffset != 0)
121 121 isfrag = B_TRUE;
122 122
123 123 src_name = addrtoname(AF_INET, &ip->ip_src);
124 124 dst_name = addrtoname(AF_INET, &ip->ip_dst);
125 125
126 126 if (flags & F_SUM) {
127 127 if (isfrag) {
128 128 (void) snprintf(get_sum_line(), MAXLINE,
129 129 "%s IP fragment ID=%d Offset=%-4d MF=%d TOS=0x%x "
130 130 "TTL=%d",
131 131 getproto(ip->ip_p),
132 132 ntohs(ip->ip_id),
133 133 fragoffset,
134 134 morefrag,
135 135 ip->ip_tos,
136 136 ip->ip_ttl);
137 137 } else {
138 138 (void) strlcpy(buff, inet_ntoa(ip->ip_dst),
139 139 sizeof (buff));
140 140 uitmp = ntohs(ip->ip_len);
141 141 (void) snprintf(get_sum_line(), MAXLINE,
142 142 "IP D=%s S=%s LEN=%u%s, ID=%d, TOS=0x%x, TTL=%d",
143 143 buff,
144 144 inet_ntoa(ip->ip_src),
145 145 uitmp,
146 146 iplen > fraglen ? "?" : "",
147 147 ntohs(ip->ip_id),
148 148 ip->ip_tos,
149 149 ip->ip_ttl);
150 150 }
151 151 }
152 152
153 153 if (flags & F_DTAIL) {
154 154 show_header("IP: ", "IP Header", iplen);
155 155 show_space();
156 156 (void) snprintf(get_line(0, 0), get_line_remain(),
157 157 "Version = %d", ip->ip_v);
158 158 (void) snprintf(get_line(0, 0), get_line_remain(),
159 159 "Header length = %d bytes", hdrlen);
160 160 (void) snprintf(get_line(0, 0), get_line_remain(),
161 161 "Type of service = 0x%02x", ip->ip_tos);
162 162 (void) snprintf(get_line(0, 0), get_line_remain(),
163 163 " xxx. .... = %d (precedence)",
164 164 ip->ip_tos >> 5);
165 165 (void) snprintf(get_line(0, 0), get_line_remain(),
166 166 " %s", getflag(ip->ip_tos, IPTOS_LOWDELAY,
167 167 "low delay", "normal delay"));
168 168 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
169 169 getflag(ip->ip_tos, IPTOS_THROUGHPUT,
170 170 "high throughput", "normal throughput"));
171 171 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
172 172 getflag(ip->ip_tos, IPTOS_RELIABILITY,
173 173 "high reliability", "normal reliability"));
174 174 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
175 175 getflag(ip->ip_tos, IPTOS_ECT,
176 176 "ECN capable transport", "not ECN capable transport"));
177 177 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
178 178 getflag(ip->ip_tos, IPTOS_CE,
179 179 "ECN congestion experienced",
180 180 "no ECN congestion experienced"));
181 181 /* warning: ip_len is signed in netinet/ip.h */
182 182 uitmp = ntohs(ip->ip_len);
183 183 (void) snprintf(get_line(0, 0), get_line_remain(),
184 184 "Total length = %u bytes%s", uitmp,
185 185 iplen > fraglen ? " -- truncated" : "");
186 186 (void) snprintf(get_line(0, 0), get_line_remain(),
187 187 "Identification = %d", ntohs(ip->ip_id));
188 188 /* warning: ip_off is signed in netinet/ip.h */
189 189 uitmp = ntohs(ip->ip_off);
190 190 (void) snprintf(get_line(0, 0), get_line_remain(),
191 191 "Flags = 0x%x", uitmp >> 12);
192 192 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
193 193 getflag(uitmp >> 8, IP_DF >> 8,
194 194 "do not fragment", "may fragment"));
195 195 (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
196 196 getflag(uitmp >> 8, IP_MF >> 8,
197 197 "more fragments", "last fragment"));
198 198 (void) snprintf(get_line(0, 0), get_line_remain(),
199 199 "Fragment offset = %u bytes",
200 200 fragoffset);
201 201 (void) snprintf(get_line(0, 0), get_line_remain(),
202 202 "Time to live = %d seconds/hops",
203 203 ip->ip_ttl);
204 204 (void) snprintf(get_line(0, 0), get_line_remain(),
205 205 "Protocol = %d (%s)", ip->ip_p,
206 206 getproto(ip->ip_p));
207 207 /*
208 208 * XXX need to compute checksum and print whether it's correct
209 209 */
210 210 (void) snprintf(get_line(0, 0), get_line_remain(),
211 211 "Header checksum = %04x",
212 212 ntohs(ip->ip_sum));
213 213 (void) snprintf(get_line(0, 0), get_line_remain(),
214 214 "Source address = %s, %s",
215 215 inet_ntoa(ip->ip_src), addrtoname(AF_INET, &ip->ip_src));
216 216 (void) snprintf(get_line(0, 0), get_line_remain(),
217 217 "Destination address = %s, %s",
218 218 inet_ntoa(ip->ip_dst), addrtoname(AF_INET, &ip->ip_dst));
219 219
220 220 /* Print IP options - if any */
221 221
222 222 print_ipoptions((const uchar_t *)(ip + 1),
223 223 hdrlen - sizeof (struct ip));
224 224 show_space();
225 225 }
226 226
227 227 /*
228 228 * If we are in detail mode, and this is not the first fragment of
229 229 * a fragmented packet, print out a little line stating this.
230 230 * Otherwise, go to the next protocol layer only if this is not a
231 231 * fragment, or we are in detail mode and this is the first fragment
232 232 * of a fragmented packet.
233 233 */
234 234 if (flags & F_DTAIL && fragoffset != 0) {
235 235 (void) snprintf(get_detail_line(0, 0), MAXLINE,
236 236 "%s: [%d byte(s) of data, continuation of IP ident=%d]",
237 237 getproto(ip->ip_p),
238 238 iplen,
239 239 ntohs(ip->ip_id));
240 240 } else if (!isfrag || (flags & F_DTAIL) && isfrag && fragoffset == 0) {
241 241 /* go to the next protocol layer */
242 242
243 243 if (fraglen > 0) {
244 244 switch (ip->ip_p) {
245 245 case IPPROTO_IP:
246 246 break;
247 247 case IPPROTO_ENCAP:
248 248 (void) interpret_ip(flags,
249 249 /* LINTED: alignment */
250 250 (const struct ip *)data, fraglen);
251 251 break;
252 252 case IPPROTO_ICMP:
253 253 (void) interpret_icmp(flags,
254 254 /* LINTED: alignment */
255 255 (struct icmp *)data, iplen, fraglen);
256 256 break;
257 257 case IPPROTO_IGMP:
258 258 interpret_igmp(flags, data, iplen, fraglen);
259 259 break;
260 260 case IPPROTO_GGP:
261 261 break;
262 262 case IPPROTO_TCP:
263 263 (void) interpret_tcp(flags,
264 264 (struct tcphdr *)data, iplen, fraglen);
265 265 break;
266 266
267 267 case IPPROTO_ESP:
268 268 (void) interpret_esp(flags, data, iplen,
269 269 fraglen);
270 270 break;
271 271 case IPPROTO_AH:
272 272 (void) interpret_ah(flags, data, iplen,
273 273 fraglen);
274 274 break;
275 275
276 276 case IPPROTO_OSPF:
277 277 interpret_ospf(flags, data, iplen, fraglen);
278 278 break;
279 279
280 280 case IPPROTO_EGP:
281 281 case IPPROTO_PUP:
282 282 break;
283 283 case IPPROTO_UDP:
284 284 (void) interpret_udp(flags,
285 285 (struct udphdr *)data, iplen, fraglen);
286 286 break;
287 287
288 288 case IPPROTO_IDP:
289 289 case IPPROTO_HELLO:
290 290 case IPPROTO_ND:
291 291 case IPPROTO_RAW:
↓ open down ↓ |
291 lines elided |
↑ open up ↑ |
292 292 break;
293 293 case IPPROTO_IPV6: /* IPV6 encap */
294 294 /* LINTED: alignment */
295 295 (void) interpret_ipv6(flags, (ip6_t *)data,
296 296 iplen);
297 297 break;
298 298 case IPPROTO_SCTP:
299 299 (void) interpret_sctp(flags,
300 300 (struct sctp_hdr *)data, iplen, fraglen);
301 301 break;
302 + case IPPROTO_DCCP:
303 + (void) interpret_dccp(flags,
304 + (struct dccphdr *)data, iplen, fraglen);
305 + break;
302 306 }
303 307 }
304 308 }
305 309
306 310 encap_levels--;
307 311 return (iplen);
308 312 }
309 313
310 314 int
311 315 interpret_ipv6(int flags, const ip6_t *ip6h, int fraglen)
312 316 {
313 317 uint8_t *data;
314 318 int hdrlen, iplen;
315 319 int version, flow, class;
316 320 uchar_t proto;
317 321 boolean_t isfrag = B_FALSE;
318 322 uint8_t extmask;
319 323 /*
320 324 * The print_srcname and print_dstname strings are the hostname
321 325 * parts of the verbose IPv6 header output, including the comma
322 326 * and the space after the litteral address strings.
323 327 */
324 328 char print_srcname[MAXHOSTNAMELEN + 2];
325 329 char print_dstname[MAXHOSTNAMELEN + 2];
326 330 char src_addrstr[INET6_ADDRSTRLEN];
327 331 char dst_addrstr[INET6_ADDRSTRLEN];
328 332
329 333 iplen = ntohs(ip6h->ip6_plen);
330 334 hdrlen = IPV6_HDR_LEN;
331 335 fraglen -= hdrlen;
332 336 if (fraglen < 0)
333 337 return (fraglen + hdrlen);
334 338 data = ((uint8_t *)ip6h) + hdrlen;
335 339
336 340 proto = ip6h->ip6_nxt;
337 341
338 342 src_name = addrtoname(AF_INET6, &ip6h->ip6_src);
339 343 dst_name = addrtoname(AF_INET6, &ip6h->ip6_dst);
340 344
341 345 /*
342 346 * Use endian-aware masks to extract traffic class and
343 347 * flowinfo. Also, flowinfo is now 20 bits and class 8
344 348 * rather than 24 and 4.
345 349 */
346 350 class = ntohl((ip6h->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20);
347 351 flow = ntohl(ip6h->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL);
348 352
349 353 /*
350 354 * NOTE: the F_SUM and F_DTAIL flags are mutually exclusive,
351 355 * so the code within the first part of the following if statement
352 356 * will not affect the detailed printing of the packet.
353 357 */
354 358 if (flags & F_SUM) {
355 359 (void) snprintf(get_sum_line(), MAXLINE,
356 360 "IPv6 S=%s D=%s LEN=%d HOPS=%d CLASS=0x%x FLOW=0x%x",
357 361 src_name, dst_name, iplen, ip6h->ip6_hops, class, flow);
358 362 } else if (flags & F_DTAIL) {
359 363
360 364 (void) inet_ntop(AF_INET6, &ip6h->ip6_src, src_addrstr,
361 365 INET6_ADDRSTRLEN);
362 366 (void) inet_ntop(AF_INET6, &ip6h->ip6_dst, dst_addrstr,
363 367 INET6_ADDRSTRLEN);
364 368
365 369 version = ntohl(ip6h->ip6_vcf) >> 28;
366 370
367 371 if (strcmp(src_name, src_addrstr) == 0) {
368 372 print_srcname[0] = '\0';
369 373 } else {
370 374 snprintf(print_srcname, sizeof (print_srcname),
371 375 ", %s", src_name);
372 376 }
373 377
374 378 if (strcmp(dst_name, dst_addrstr) == 0) {
375 379 print_dstname[0] = '\0';
376 380 } else {
377 381 snprintf(print_dstname, sizeof (print_dstname),
378 382 ", %s", dst_name);
379 383 }
380 384
381 385 show_header("IPv6: ", "IPv6 Header", iplen);
382 386 show_space();
383 387
384 388 (void) snprintf(get_line(0, 0), get_line_remain(),
385 389 "Version = %d", version);
386 390 (void) snprintf(get_line(0, 0), get_line_remain(),
387 391 "Traffic Class = %d", class);
388 392 (void) snprintf(get_line(0, 0), get_line_remain(),
389 393 "Flow label = 0x%x", flow);
390 394 (void) snprintf(get_line(0, 0), get_line_remain(),
391 395 "Payload length = %d", iplen);
392 396 (void) snprintf(get_line(0, 0), get_line_remain(),
393 397 "Next Header = %d (%s)", proto,
394 398 getproto(proto));
395 399 (void) snprintf(get_line(0, 0), get_line_remain(),
396 400 "Hop Limit = %d", ip6h->ip6_hops);
397 401 (void) snprintf(get_line(0, 0), get_line_remain(),
398 402 "Source address = %s%s", src_addrstr, print_srcname);
399 403 (void) snprintf(get_line(0, 0), get_line_remain(),
400 404 "Destination address = %s%s", dst_addrstr, print_dstname);
401 405
402 406 show_space();
403 407 }
404 408
405 409 /*
406 410 * Print IPv6 Extension Headers, or skip them in the summary case.
407 411 * Set isfrag to true if one of the extension headers encounterred
408 412 * was a fragment header.
409 413 */
410 414 if (proto == IPPROTO_HOPOPTS || proto == IPPROTO_DSTOPTS ||
411 415 proto == IPPROTO_ROUTING || proto == IPPROTO_FRAGMENT) {
412 416 extmask = print_ipv6_extensions(flags, &data, &proto, &iplen,
413 417 &fraglen);
414 418 if ((extmask & SNOOP_FRAGMENT) != 0) {
415 419 isfrag = B_TRUE;
416 420 }
417 421 }
418 422
419 423 /*
420 424 * We only want to print upper layer information if this is not
421 425 * a fragment, or if we're printing in detail. Note that the
422 426 * proto variable will be set to IPPROTO_NONE if this is a fragment
423 427 * with a non-zero fragment offset.
424 428 */
425 429 if (!isfrag || flags & F_DTAIL) {
426 430 /* go to the next protocol layer */
427 431
428 432 switch (proto) {
429 433 case IPPROTO_IP:
430 434 break;
431 435 case IPPROTO_ENCAP:
432 436 /* LINTED: alignment */
433 437 (void) interpret_ip(flags, (const struct ip *)data,
434 438 fraglen);
435 439 break;
436 440 case IPPROTO_ICMPV6:
437 441 /* LINTED: alignment */
438 442 (void) interpret_icmpv6(flags, (icmp6_t *)data, iplen,
439 443 fraglen);
440 444 break;
441 445 case IPPROTO_IGMP:
442 446 interpret_igmp(flags, data, iplen, fraglen);
443 447 break;
444 448 case IPPROTO_GGP:
445 449 break;
446 450 case IPPROTO_TCP:
447 451 (void) interpret_tcp(flags, (struct tcphdr *)data,
448 452 iplen, fraglen);
449 453 break;
450 454 case IPPROTO_ESP:
451 455 (void) interpret_esp(flags, data, iplen, fraglen);
452 456 break;
453 457 case IPPROTO_AH:
454 458 (void) interpret_ah(flags, data, iplen, fraglen);
455 459 break;
456 460 case IPPROTO_EGP:
457 461 case IPPROTO_PUP:
458 462 break;
459 463 case IPPROTO_UDP:
460 464 (void) interpret_udp(flags, (struct udphdr *)data,
461 465 iplen, fraglen);
462 466 break;
463 467 case IPPROTO_IDP:
464 468 case IPPROTO_HELLO:
465 469 case IPPROTO_ND:
466 470 case IPPROTO_RAW:
467 471 break;
468 472 case IPPROTO_IPV6:
469 473 /* LINTED: alignment */
↓ open down ↓ |
158 lines elided |
↑ open up ↑ |
470 474 (void) interpret_ipv6(flags, (const ip6_t *)data,
471 475 iplen);
472 476 break;
473 477 case IPPROTO_SCTP:
474 478 (void) interpret_sctp(flags, (struct sctp_hdr *)data,
475 479 iplen, fraglen);
476 480 break;
477 481 case IPPROTO_OSPF:
478 482 interpret_ospf6(flags, data, iplen, fraglen);
479 483 break;
484 + case IPPROTO_DCCP:
485 + (void) interpret_dccp(flags, (struct dccphdr *)data,
486 + iplen, fraglen);
487 + break;
480 488 }
481 489 }
482 490
483 491 return (iplen);
484 492 }
485 493
486 494 /*
487 495 * ip_ext: data including the extension header.
488 496 * iplen: length of the data remaining in the packet.
489 497 * Returns a mask of IPv6 extension headers it processed.
490 498 */
491 499 uint8_t
492 500 print_ipv6_extensions(int flags, uint8_t **hdr, uint8_t *next, int *iplen,
493 501 int *fraglen)
494 502 {
495 503 uint8_t *data_ptr;
496 504 uchar_t proto = *next;
497 505 boolean_t is_extension_header;
498 506 struct ip6_hbh *ipv6ext_hbh;
499 507 struct ip6_dest *ipv6ext_dest;
500 508 struct ip6_rthdr *ipv6ext_rthdr;
501 509 struct ip6_frag *ipv6ext_frag;
502 510 uint32_t exthdrlen;
503 511 uint8_t extmask = 0;
504 512
505 513 if ((hdr == NULL) || (*hdr == NULL) || (next == NULL) || (iplen == 0))
506 514 return (0);
507 515
508 516 data_ptr = *hdr;
509 517 is_extension_header = B_TRUE;
510 518 while (is_extension_header) {
511 519
512 520 /*
513 521 * There must be at least enough data left to read the
514 522 * next header and header length fields from the next
515 523 * header.
516 524 */
517 525 if (*fraglen < 2) {
518 526 return (extmask);
519 527 }
520 528
521 529 switch (proto) {
522 530 case IPPROTO_HOPOPTS:
523 531 ipv6ext_hbh = (struct ip6_hbh *)data_ptr;
524 532 exthdrlen = 8 + ipv6ext_hbh->ip6h_len * 8;
525 533 if (*fraglen <= exthdrlen) {
526 534 return (extmask);
527 535 }
528 536 prt_hbh_options(flags, ipv6ext_hbh);
529 537 extmask |= SNOOP_HOPOPTS;
530 538 proto = ipv6ext_hbh->ip6h_nxt;
531 539 break;
532 540 case IPPROTO_DSTOPTS:
533 541 ipv6ext_dest = (struct ip6_dest *)data_ptr;
534 542 exthdrlen = 8 + ipv6ext_dest->ip6d_len * 8;
535 543 if (*fraglen <= exthdrlen) {
536 544 return (extmask);
537 545 }
538 546 prt_dest_options(flags, ipv6ext_dest);
539 547 extmask |= SNOOP_DSTOPTS;
540 548 proto = ipv6ext_dest->ip6d_nxt;
541 549 break;
542 550 case IPPROTO_ROUTING:
543 551 ipv6ext_rthdr = (struct ip6_rthdr *)data_ptr;
544 552 exthdrlen = 8 + ipv6ext_rthdr->ip6r_len * 8;
545 553 if (*fraglen <= exthdrlen) {
546 554 return (extmask);
547 555 }
548 556 prt_routing_hdr(flags, ipv6ext_rthdr);
549 557 extmask |= SNOOP_ROUTING;
550 558 proto = ipv6ext_rthdr->ip6r_nxt;
551 559 break;
552 560 case IPPROTO_FRAGMENT:
553 561 /* LINTED: alignment */
554 562 ipv6ext_frag = (struct ip6_frag *)data_ptr;
555 563 exthdrlen = sizeof (struct ip6_frag);
556 564 if (*fraglen <= exthdrlen) {
557 565 return (extmask);
558 566 }
559 567 prt_fragment_hdr(flags, ipv6ext_frag);
560 568 extmask |= SNOOP_FRAGMENT;
561 569 /*
562 570 * If this is not the first fragment, forget about
563 571 * the rest of the packet, snoop decoding is
564 572 * stateless.
565 573 */
566 574 if ((ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK) != 0)
567 575 proto = IPPROTO_NONE;
568 576 else
569 577 proto = ipv6ext_frag->ip6f_nxt;
570 578 break;
571 579 default:
572 580 is_extension_header = B_FALSE;
573 581 break;
574 582 }
575 583
576 584 if (is_extension_header) {
577 585 *iplen -= exthdrlen;
578 586 *fraglen -= exthdrlen;
579 587 data_ptr += exthdrlen;
580 588 }
581 589 }
582 590
583 591 *next = proto;
584 592 *hdr = data_ptr;
585 593 return (extmask);
586 594 }
587 595
588 596 static void
589 597 print_ipoptions(const uchar_t *opt, int optlen)
590 598 {
591 599 int len;
592 600 int remain;
593 601 char *line;
594 602 const char *truncstr;
595 603
596 604 if (optlen <= 0) {
597 605 (void) snprintf(get_line(0, 0), get_line_remain(),
598 606 "No options");
599 607 return;
600 608 }
601 609
602 610 (void) snprintf(get_line(0, 0), get_line_remain(),
603 611 "Options: (%d bytes)", optlen);
604 612
605 613 while (optlen > 0) {
606 614 line = get_line(0, 0);
607 615 remain = get_line_remain();
608 616 len = opt[1];
609 617 truncstr = len > optlen ? "?" : "";
610 618 switch (opt[0]) {
611 619 case IPOPT_EOL:
612 620 (void) strlcpy(line, " - End of option list", remain);
613 621 return;
614 622 case IPOPT_NOP:
615 623 (void) strlcpy(line, " - No op", remain);
616 624 len = 1;
617 625 break;
618 626 case IPOPT_RR:
619 627 (void) snprintf(line, remain,
620 628 " - Record route (%d bytes%s)", len, truncstr);
621 629 print_route(opt);
622 630 break;
623 631 case IPOPT_TS:
624 632 (void) snprintf(line, remain,
625 633 " - Time stamp (%d bytes%s)", len, truncstr);
626 634 break;
627 635 case IPOPT_SECURITY:
628 636 (void) snprintf(line, remain, " - RIPSO (%d bytes%s)",
629 637 len, truncstr);
630 638 print_ripso(opt);
631 639 break;
632 640 case IPOPT_COMSEC:
633 641 (void) snprintf(line, remain, " - CIPSO (%d bytes%s)",
634 642 len, truncstr);
635 643 print_cipso(opt);
636 644 break;
637 645 case IPOPT_LSRR:
638 646 (void) snprintf(line, remain,
639 647 " - Loose source route (%d bytes%s)", len,
640 648 truncstr);
641 649 print_route(opt);
642 650 break;
643 651 case IPOPT_SATID:
644 652 (void) snprintf(line, remain,
645 653 " - SATNET Stream id (%d bytes%s)",
646 654 len, truncstr);
647 655 break;
648 656 case IPOPT_SSRR:
649 657 (void) snprintf(line, remain,
650 658 " - Strict source route, (%d bytes%s)", len,
651 659 truncstr);
652 660 print_route(opt);
653 661 break;
654 662 default:
655 663 (void) snprintf(line, remain,
656 664 " - Option %d (unknown - %d bytes%s) %s",
657 665 opt[0], len, truncstr,
658 666 tohex((char *)&opt[2], len - 2));
659 667 break;
660 668 }
661 669 if (len <= 0) {
662 670 (void) snprintf(line, remain,
663 671 " - Incomplete option len %d", len);
664 672 break;
665 673 }
666 674 opt += len;
667 675 optlen -= len;
668 676 }
669 677 }
670 678
671 679 static void
672 680 print_route(const uchar_t *opt)
673 681 {
674 682 int len, pointer, remain;
675 683 struct in_addr addr;
676 684 char *line;
677 685
678 686 len = opt[1];
679 687 pointer = opt[2];
680 688
681 689 (void) snprintf(get_line(0, 0), get_line_remain(),
682 690 " Pointer = %d", pointer);
683 691
684 692 pointer -= IPOPT_MINOFF;
685 693 opt += (IPOPT_OFFSET + 1);
686 694 len -= (IPOPT_OFFSET + 1);
687 695
688 696 while (len > 0) {
689 697 line = get_line(0, 0);
690 698 remain = get_line_remain();
691 699 memcpy((char *)&addr, opt, sizeof (addr));
692 700 if (addr.s_addr == INADDR_ANY)
693 701 (void) strlcpy(line, " -", remain);
694 702 else
695 703 (void) snprintf(line, remain, " %s",
696 704 addrtoname(AF_INET, &addr));
697 705 if (pointer == 0)
698 706 (void) strlcat(line, " <-- (current)", remain);
699 707
700 708 opt += sizeof (addr);
701 709 len -= sizeof (addr);
702 710 pointer -= sizeof (addr);
703 711 }
704 712 }
705 713
706 714 char *
707 715 getproto(int p)
708 716 {
709 717 switch (p) {
710 718 case IPPROTO_HOPOPTS: return ("IPv6-HopOpts");
711 719 case IPPROTO_IPV6: return ("IPv6");
712 720 case IPPROTO_ROUTING: return ("IPv6-Route");
713 721 case IPPROTO_FRAGMENT: return ("IPv6-Frag");
714 722 case IPPROTO_RSVP: return ("RSVP");
715 723 case IPPROTO_ENCAP: return ("IP-in-IP");
716 724 case IPPROTO_AH: return ("AH");
717 725 case IPPROTO_ESP: return ("ESP");
718 726 case IPPROTO_ICMP: return ("ICMP");
719 727 case IPPROTO_ICMPV6: return ("ICMPv6");
720 728 case IPPROTO_DSTOPTS: return ("IPv6-DstOpts");
721 729 case IPPROTO_IGMP: return ("IGMP");
722 730 case IPPROTO_GGP: return ("GGP");
723 731 case IPPROTO_TCP: return ("TCP");
724 732 case IPPROTO_EGP: return ("EGP");
725 733 case IPPROTO_PUP: return ("PUP");
726 734 case IPPROTO_UDP: return ("UDP");
727 735 case IPPROTO_IDP: return ("IDP");
728 736 case IPPROTO_HELLO: return ("HELLO");
729 737 case IPPROTO_ND: return ("ND");
730 738 case IPPROTO_EON: return ("EON");
731 739 case IPPROTO_RAW: return ("RAW");
732 740 case IPPROTO_OSPF: return ("OSPF");
733 741 default: return ("");
734 742 }
735 743 }
736 744
737 745 static void
738 746 prt_routing_hdr(int flags, const struct ip6_rthdr *ipv6ext_rthdr)
739 747 {
740 748 uint8_t nxt_hdr;
741 749 uint8_t type;
742 750 uint32_t len;
743 751 uint8_t segleft;
744 752 uint32_t numaddrs;
745 753 int i;
746 754 struct ip6_rthdr0 *ipv6ext_rthdr0;
747 755 struct in6_addr *addrs;
748 756 char addr[INET6_ADDRSTRLEN];
749 757
750 758 /* in summary mode, we don't do anything. */
751 759 if (flags & F_SUM) {
752 760 return;
753 761 }
754 762
755 763 nxt_hdr = ipv6ext_rthdr->ip6r_nxt;
756 764 type = ipv6ext_rthdr->ip6r_type;
757 765 len = 8 * (ipv6ext_rthdr->ip6r_len + 1);
758 766 segleft = ipv6ext_rthdr->ip6r_segleft;
759 767
760 768 show_header("IPv6-Route: ", "IPv6 Routing Header", 0);
761 769 show_space();
762 770
763 771 (void) snprintf(get_line(0, 0), get_line_remain(),
764 772 "Next header = %d (%s)", nxt_hdr, getproto(nxt_hdr));
765 773 (void) snprintf(get_line(0, 0), get_line_remain(),
766 774 "Header length = %d", len);
767 775 (void) snprintf(get_line(0, 0), get_line_remain(),
768 776 "Routing type = %d", type);
769 777 (void) snprintf(get_line(0, 0), get_line_remain(),
770 778 "Segments left = %d", segleft);
771 779
772 780 if (type == IPV6_RTHDR_TYPE_0) {
773 781 /*
774 782 * XXX This loop will print all addresses in the routing header,
775 783 * XXX not just the segments left.
776 784 * XXX (The header length field is twice the number of
777 785 * XXX addresses)
778 786 * XXX At some future time, we may want to change this
779 787 * XXX to differentiate between the hops yet to do
780 788 * XXX and the hops already taken.
781 789 */
782 790 /* LINTED: alignment */
783 791 ipv6ext_rthdr0 = (struct ip6_rthdr0 *)ipv6ext_rthdr;
784 792 numaddrs = ipv6ext_rthdr0->ip6r0_len / 2;
785 793 addrs = (struct in6_addr *)(ipv6ext_rthdr0 + 1);
786 794 for (i = 0; i < numaddrs; i++) {
787 795 (void) inet_ntop(AF_INET6, &addrs[i], addr,
788 796 INET6_ADDRSTRLEN);
789 797 (void) snprintf(get_line(0, 0), get_line_remain(),
790 798 "address[%d]=%s", i, addr);
791 799 }
792 800 }
793 801
794 802 show_space();
795 803 }
796 804
797 805 static void
798 806 prt_fragment_hdr(int flags, const struct ip6_frag *ipv6ext_frag)
799 807 {
800 808 boolean_t morefrag;
801 809 uint16_t fragoffset;
802 810 uint8_t nxt_hdr;
803 811 uint32_t fragident;
804 812
805 813 /* extract the various fields from the fragment header */
806 814 nxt_hdr = ipv6ext_frag->ip6f_nxt;
807 815 morefrag = (ipv6ext_frag->ip6f_offlg & IP6F_MORE_FRAG) == 0
808 816 ? B_FALSE : B_TRUE;
809 817 fragoffset = ntohs(ipv6ext_frag->ip6f_offlg & IP6F_OFF_MASK);
810 818 fragident = ntohl(ipv6ext_frag->ip6f_ident);
811 819
812 820 if (flags & F_SUM) {
813 821 (void) snprintf(get_sum_line(), MAXLINE,
814 822 "IPv6 fragment ID=%u Offset=%-4d MF=%d",
815 823 fragident,
816 824 fragoffset,
817 825 morefrag);
818 826 } else { /* F_DTAIL */
819 827 show_header("IPv6-Frag: ", "IPv6 Fragment Header", 0);
820 828 show_space();
821 829
822 830 (void) snprintf(get_line(0, 0), get_line_remain(),
823 831 "Next Header = %d (%s)", nxt_hdr, getproto(nxt_hdr));
824 832 (void) snprintf(get_line(0, 0), get_line_remain(),
825 833 "Fragment Offset = %d", fragoffset);
826 834 (void) snprintf(get_line(0, 0), get_line_remain(),
827 835 "More Fragments Flag = %s", morefrag ? "true" : "false");
828 836 (void) snprintf(get_line(0, 0), get_line_remain(),
829 837 "Identification = %u", fragident);
830 838
831 839 show_space();
832 840 }
833 841 }
834 842
835 843 static void
836 844 print_ip6opt_ls(const uchar_t *data, unsigned int op_len)
837 845 {
838 846 uint32_t doi;
839 847 uint8_t sotype, solen;
840 848 uint16_t value, value2;
841 849 char *cp;
842 850 int remlen;
843 851 boolean_t printed;
844 852
845 853 (void) snprintf(get_line(0, 0), get_line_remain(),
846 854 "Labeled Security Option len = %u bytes%s", op_len,
847 855 op_len < sizeof (uint32_t) || (op_len & 1) != 0 ? "?" : "");
848 856 if (op_len < sizeof (uint32_t))
849 857 return;
850 858 GETINT32(doi, data);
851 859 (void) snprintf(get_line(0, 0), get_line_remain(),
852 860 " DOI = %d (%s)", doi, doi == IP6LS_DOI_V4 ? "IPv4" : "???");
853 861 op_len -= sizeof (uint32_t);
854 862 while (op_len > 0) {
855 863 GETINT8(sotype, data);
856 864 if (op_len < 2) {
857 865 (void) snprintf(get_line(0, 0), get_line_remain(),
858 866 " truncated %u suboption (no len)", sotype);
859 867 break;
860 868 }
861 869 GETINT8(solen, data);
862 870 if (solen < 2 || solen > op_len) {
863 871 (void) snprintf(get_line(0, 0), get_line_remain(),
864 872 " bad %u suboption (len 2 <= %u <= %u)",
865 873 sotype, solen, op_len);
866 874 if (solen < 2)
867 875 solen = 2;
868 876 if (solen > op_len)
869 877 solen = op_len;
870 878 }
871 879 op_len -= solen;
872 880 solen -= 2;
873 881 cp = get_line(0, 0);
874 882 remlen = get_line_remain();
875 883 (void) strlcpy(cp, " ", remlen);
876 884 cp += 4;
877 885 remlen -= 4;
878 886 printed = B_TRUE;
879 887 switch (sotype) {
880 888 case IP6LS_TT_LEVEL:
881 889 if (solen != 2) {
882 890 printed = B_FALSE;
883 891 break;
884 892 }
885 893 GETINT16(value, data);
886 894 (void) snprintf(cp, remlen, "Level %u", value);
887 895 solen = 0;
888 896 break;
889 897 case IP6LS_TT_VECTOR:
890 898 (void) strlcpy(cp, "Bit-Vector: ", remlen);
891 899 remlen -= strlen(cp);
892 900 cp += strlen(cp);
893 901 while (solen > 1) {
894 902 GETINT16(value, data);
895 903 solen -= 2;
896 904 (void) snprintf(cp, remlen, "%04x", value);
897 905 remlen -= strlen(cp);
898 906 cp += strlen(cp);
899 907 }
900 908 break;
901 909 case IP6LS_TT_ENUM:
902 910 (void) strlcpy(cp, "Enumeration:", remlen);
903 911 remlen -= strlen(cp);
904 912 cp += strlen(cp);
905 913 while (solen > 1) {
906 914 GETINT16(value, data);
907 915 solen -= 2;
908 916 (void) snprintf(cp, remlen, " %u", value);
909 917 remlen -= strlen(cp);
910 918 cp += strlen(cp);
911 919 }
912 920 break;
913 921 case IP6LS_TT_RANGES:
914 922 (void) strlcpy(cp, "Ranges:", remlen);
915 923 remlen -= strlen(cp);
916 924 cp += strlen(cp);
917 925 while (solen > 3) {
918 926 GETINT16(value, data);
919 927 GETINT16(value2, data);
920 928 solen -= 4;
921 929 (void) snprintf(cp, remlen, " %u-%u", value,
922 930 value2);
923 931 remlen -= strlen(cp);
924 932 cp += strlen(cp);
925 933 }
926 934 break;
927 935 case IP6LS_TT_V4:
928 936 (void) strlcpy(cp, "IPv4 Option", remlen);
929 937 print_ipoptions(data, solen);
930 938 solen = 0;
931 939 break;
932 940 case IP6LS_TT_DEST:
933 941 (void) snprintf(cp, remlen,
934 942 "Destination-Only Data length %u", solen);
935 943 solen = 0;
936 944 break;
937 945 default:
938 946 (void) snprintf(cp, remlen,
939 947 " unknown %u suboption (len %u)", sotype, solen);
940 948 solen = 0;
941 949 break;
942 950 }
943 951 if (solen != 0) {
944 952 if (printed) {
945 953 cp = get_line(0, 0);
946 954 remlen = get_line_remain();
947 955 }
948 956 (void) snprintf(cp, remlen,
949 957 " malformed %u suboption (remaining %u)",
950 958 sotype, solen);
951 959 data += solen;
952 960 }
953 961 }
954 962 }
955 963
956 964 static void
957 965 prt_hbh_options(int flags, const struct ip6_hbh *ipv6ext_hbh)
958 966 {
959 967 const uint8_t *data, *ndata;
960 968 uint32_t len;
961 969 uint8_t op_type;
962 970 uint8_t op_len;
963 971 uint8_t nxt_hdr;
964 972
965 973 /* in summary mode, we don't do anything. */
966 974 if (flags & F_SUM) {
967 975 return;
968 976 }
969 977
970 978 show_header("IPv6-HopOpts: ", "IPv6 Hop-by-Hop Options Header", 0);
971 979 show_space();
972 980
973 981 /*
974 982 * Store the lengh of this ext hdr in bytes. The caller has
975 983 * ensured that there is at least len bytes of data left.
976 984 */
977 985 len = ipv6ext_hbh->ip6h_len * 8 + 8;
978 986
979 987 ndata = (const uint8_t *)ipv6ext_hbh + 2;
980 988 len -= 2;
981 989
982 990 nxt_hdr = ipv6ext_hbh->ip6h_nxt;
983 991 (void) snprintf(get_line(0, 0), get_line_remain(),
984 992 "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr));
985 993
986 994 while (len > 0) {
987 995 data = ndata;
988 996 GETINT8(op_type, data);
989 997 /* This is the only one-octet IPv6 option */
990 998 if (op_type == IP6OPT_PAD1) {
991 999 (void) snprintf(get_line(0, 0), get_line_remain(),
992 1000 "pad1 option ");
993 1001 len--;
994 1002 ndata = data;
995 1003 continue;
996 1004 }
997 1005 GETINT8(op_len, data);
998 1006 if (len < 2 || op_len + 2 > len) {
999 1007 (void) snprintf(get_line(0, 0), get_line_remain(),
1000 1008 "Error: option %u truncated (%u + 2 > %u)",
1001 1009 op_type, op_len, len);
1002 1010 op_len = len - 2;
1003 1011 /*
1004 1012 * Continue processing the malformed option so that we
1005 1013 * can display as much as possible.
1006 1014 */
1007 1015 }
1008 1016
1009 1017 /* advance pointers to the next option */
1010 1018 len -= op_len + 2;
1011 1019 ndata = data + op_len;
1012 1020
1013 1021 /* process this option */
1014 1022 switch (op_type) {
1015 1023 case IP6OPT_PADN:
1016 1024 (void) snprintf(get_line(0, 0), get_line_remain(),
1017 1025 "padN option len = %u", op_len);
1018 1026 break;
1019 1027 case IP6OPT_JUMBO: {
1020 1028 uint32_t payload_len;
1021 1029
1022 1030 (void) snprintf(get_line(0, 0), get_line_remain(),
1023 1031 "Jumbo Payload Option len = %u bytes%s", op_len,
1024 1032 op_len == sizeof (uint32_t) ? "" : "?");
1025 1033 if (op_len == sizeof (uint32_t)) {
1026 1034 GETINT32(payload_len, data);
1027 1035 (void) snprintf(get_line(0, 0),
1028 1036 get_line_remain(),
1029 1037 "Jumbo Payload Length = %u bytes",
1030 1038 payload_len);
1031 1039 }
1032 1040 break;
1033 1041 }
1034 1042 case IP6OPT_ROUTER_ALERT: {
1035 1043 uint16_t value;
1036 1044 const char *label[] = {"MLD", "RSVP", "AN"};
1037 1045
1038 1046 (void) snprintf(get_line(0, 0), get_line_remain(),
1039 1047 "Router Alert Option len = %u bytes%s", op_len,
1040 1048 op_len == sizeof (uint16_t) ? "" : "?");
1041 1049 if (op_len == sizeof (uint16_t)) {
1042 1050 GETINT16(value, data);
1043 1051 (void) snprintf(get_line(0, 0),
1044 1052 get_line_remain(),
1045 1053 "Alert Type = %d (%s)", value,
1046 1054 value < sizeof (label) / sizeof (label[0]) ?
1047 1055 label[value] : "???");
1048 1056 }
1049 1057 break;
1050 1058 }
1051 1059 case IP6OPT_LS:
1052 1060 print_ip6opt_ls(data, op_len);
1053 1061 break;
1054 1062 default:
1055 1063 (void) snprintf(get_line(0, 0), get_line_remain(),
1056 1064 "Option type = %u, len = %u", op_type, op_len);
1057 1065 break;
1058 1066 }
1059 1067 }
1060 1068
1061 1069 show_space();
1062 1070 }
1063 1071
1064 1072 static void
1065 1073 prt_dest_options(int flags, const struct ip6_dest *ipv6ext_dest)
1066 1074 {
1067 1075 const uint8_t *data, *ndata;
1068 1076 uint32_t len;
1069 1077 uint8_t op_type;
1070 1078 uint32_t op_len;
1071 1079 uint8_t nxt_hdr;
1072 1080 uint8_t value;
1073 1081
1074 1082 /* in summary mode, we don't do anything. */
1075 1083 if (flags & F_SUM) {
1076 1084 return;
1077 1085 }
1078 1086
1079 1087 show_header("IPv6-DstOpts: ", "IPv6 Destination Options Header", 0);
1080 1088 show_space();
1081 1089
1082 1090 /*
1083 1091 * Store the length of this ext hdr in bytes. The caller has
1084 1092 * ensured that there is at least len bytes of data left.
1085 1093 */
1086 1094 len = ipv6ext_dest->ip6d_len * 8 + 8;
1087 1095
1088 1096 ndata = (const uint8_t *)ipv6ext_dest + 2; /* skip hdr/len */
1089 1097 len -= 2;
1090 1098
1091 1099 nxt_hdr = ipv6ext_dest->ip6d_nxt;
1092 1100 (void) snprintf(get_line(0, 0), get_line_remain(),
1093 1101 "Next Header = %u (%s)", nxt_hdr, getproto(nxt_hdr));
1094 1102
1095 1103 while (len > 0) {
1096 1104 data = ndata;
1097 1105 GETINT8(op_type, data);
1098 1106 if (op_type == IP6OPT_PAD1) {
1099 1107 (void) snprintf(get_line(0, 0), get_line_remain(),
1100 1108 "pad1 option ");
1101 1109 len--;
1102 1110 ndata = data;
1103 1111 continue;
1104 1112 }
1105 1113 GETINT8(op_len, data);
1106 1114 if (len < 2 || op_len + 2 > len) {
1107 1115 (void) snprintf(get_line(0, 0), get_line_remain(),
1108 1116 "Error: option %u truncated (%u + 2 > %u)",
1109 1117 op_type, op_len, len);
1110 1118 op_len = len - 2;
1111 1119 /*
1112 1120 * Continue processing the malformed option so that we
1113 1121 * can display as much as possible.
1114 1122 */
1115 1123 }
1116 1124
1117 1125 /* advance pointers to the next option */
1118 1126 len -= op_len + 2;
1119 1127 ndata = data + op_len;
1120 1128
1121 1129 /* process this option */
1122 1130 switch (op_type) {
1123 1131 case IP6OPT_PADN:
1124 1132 (void) snprintf(get_line(0, 0), get_line_remain(),
1125 1133 "padN option len = %u", op_len);
1126 1134 break;
1127 1135 case IP6OPT_TUNNEL_LIMIT:
1128 1136 GETINT8(value, data);
1129 1137 (void) snprintf(get_line(0, 0), get_line_remain(),
1130 1138 "tunnel encapsulation limit len = %d, value = %d",
1131 1139 op_len, value);
1132 1140 break;
1133 1141 case IP6OPT_LS:
1134 1142 print_ip6opt_ls(data, op_len);
1135 1143 break;
1136 1144 default:
1137 1145 (void) snprintf(get_line(0, 0), get_line_remain(),
1138 1146 "Option type = %u, len = %u", op_type, op_len);
1139 1147 break;
1140 1148 }
1141 1149 }
1142 1150
1143 1151 show_space();
1144 1152 }
1145 1153
1146 1154 #define ALABEL_MAXLEN 256
1147 1155
1148 1156 static char ascii_label[ALABEL_MAXLEN];
1149 1157 static char *plabel = ascii_label;
1150 1158
1151 1159 struct snoop_pair {
1152 1160 int val;
1153 1161 const char *name;
1154 1162 };
1155 1163
1156 1164 static struct snoop_pair ripso_class_tbl[] = {
1157 1165 TSOL_CL_TOP_SECRET, "TOP SECRET",
1158 1166 TSOL_CL_SECRET, "SECRET",
1159 1167 TSOL_CL_CONFIDENTIAL, "CONFIDENTIAL",
1160 1168 TSOL_CL_UNCLASSIFIED, "UNCLASSIFIED",
1161 1169 -1, NULL
1162 1170 };
1163 1171
1164 1172 static struct snoop_pair ripso_prot_tbl[] = {
1165 1173 TSOL_PA_GENSER, "GENSER",
1166 1174 TSOL_PA_SIOP_ESI, "SIOP-ESI",
1167 1175 TSOL_PA_SCI, "SCI",
1168 1176 TSOL_PA_NSA, "NSA",
1169 1177 TSOL_PA_DOE, "DOE",
1170 1178 0x04, "UNASSIGNED",
1171 1179 0x02, "UNASSIGNED",
1172 1180 -1, NULL
1173 1181 };
1174 1182
1175 1183 static struct snoop_pair *
1176 1184 get_pair_byval(struct snoop_pair pairlist[], int val)
1177 1185 {
1178 1186 int i;
1179 1187
1180 1188 for (i = 0; pairlist[i].name != NULL; i++)
1181 1189 if (pairlist[i].val == val)
1182 1190 return (&pairlist[i]);
1183 1191 return (NULL);
1184 1192 }
1185 1193
1186 1194 static void
1187 1195 print_ripso(const uchar_t *opt)
1188 1196 {
1189 1197 struct snoop_pair *ripso_class;
1190 1198 int i, index, prot_len;
1191 1199 boolean_t first_prot;
1192 1200 char line[100], *ptr;
1193 1201
1194 1202 prot_len = opt[1] - 3;
1195 1203 if (prot_len < 0)
1196 1204 return;
1197 1205
1198 1206 show_header("RIPSO: ", "Revised IP Security Option", 0);
1199 1207 show_space();
1200 1208
1201 1209 (void) snprintf(get_line(0, 0), get_line_remain(),
1202 1210 "Type = Basic Security Option (%d), Length = %d", opt[0], opt[1]);
1203 1211
1204 1212 /*
1205 1213 * Display Classification Level
1206 1214 */
1207 1215 ripso_class = get_pair_byval(ripso_class_tbl, (int)opt[2]);
1208 1216 if (ripso_class != NULL)
1209 1217 (void) snprintf(get_line(0, 0), get_line_remain(),
1210 1218 "Classification = Unknown (0x%02x)", opt[2]);
1211 1219 else
1212 1220 (void) snprintf(get_line(0, 0), get_line_remain(),
1213 1221 "Classification = %s (0x%02x)",
1214 1222 ripso_class->name, ripso_class->val);
1215 1223
1216 1224 /*
1217 1225 * Display Protection Authority Flags
1218 1226 */
1219 1227 (void) snprintf(line, sizeof (line), "Protection Authority = ");
1220 1228 ptr = line;
1221 1229 first_prot = B_TRUE;
1222 1230 for (i = 0; i < prot_len; i++) {
1223 1231 index = 0;
1224 1232 while (ripso_prot_tbl[index].name != NULL) {
1225 1233 if (opt[3 + i] & ripso_prot_tbl[index].val) {
1226 1234 ptr = strchr(ptr, 0);
1227 1235 if (!first_prot) {
1228 1236 (void) strlcpy(ptr, ", ",
1229 1237 sizeof (line) - (ptr - line));
1230 1238 ptr = strchr(ptr, 0);
1231 1239 }
1232 1240 (void) snprintf(ptr,
1233 1241 sizeof (line) - (ptr - line),
1234 1242 "%s (0x%02x)",
1235 1243 ripso_prot_tbl[index].name,
1236 1244 ripso_prot_tbl[index].val);
1237 1245 }
1238 1246 index++;
1239 1247 }
1240 1248 if ((opt[3 + i] & 1) == 0)
1241 1249 break;
1242 1250 }
1243 1251 if (!first_prot)
1244 1252 (void) snprintf(get_line(0, 0), get_line_remain(), "%s", line);
1245 1253 else
1246 1254 (void) snprintf(get_line(0, 0), get_line_remain(), "%sNone",
1247 1255 line);
1248 1256 }
1249 1257
1250 1258 #define CIPSO_GENERIC_ARRAY_LEN 200
1251 1259
1252 1260 /*
1253 1261 * Return 1 if CIPSO SL and Categories are all 1's; 0 otherwise.
1254 1262 *
1255 1263 * Note: opt starts with "Tag Type":
1256 1264 *
1257 1265 * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)|
1258 1266 *
1259 1267 */
1260 1268 static boolean_t
1261 1269 cipso_high(const uchar_t *opt)
1262 1270 {
1263 1271 int i;
1264 1272
1265 1273 if (((int)opt[1] + 6) < IP_MAX_OPT_LENGTH)
1266 1274 return (B_FALSE);
1267 1275 for (i = 0; i < ((int)opt[1] - 3); i++)
1268 1276 if (opt[3 + i] != 0xff)
1269 1277 return (B_FALSE);
1270 1278 return (B_TRUE);
1271 1279 }
1272 1280
1273 1281 /*
1274 1282 * Converts CIPSO label to SL.
1275 1283 *
1276 1284 * Note: opt starts with "Tag Type":
1277 1285 *
1278 1286 * |tag_type(1)|tag_length(1)|align(1)|sl(1)|categories(variable)|
1279 1287 *
1280 1288 */
1281 1289 static void
1282 1290 cipso2sl(const uchar_t *opt, bslabel_t *sl, int *high)
1283 1291 {
1284 1292 int i, taglen;
1285 1293 uchar_t *q = (uchar_t *)&((_bslabel_impl_t *)sl)->compartments;
1286 1294
1287 1295 *high = 0;
1288 1296 taglen = opt[1];
1289 1297 memset((caddr_t)sl, 0, sizeof (bslabel_t));
1290 1298
1291 1299 if (cipso_high(opt)) {
1292 1300 BSLHIGH(sl);
1293 1301 *high = 1;
1294 1302 } else {
1295 1303 LCLASS_SET((_bslabel_impl_t *)sl, opt[3]);
1296 1304 for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++)
1297 1305 q[i] = opt[TSOL_TT1_MIN_LENGTH + i];
1298 1306 }
1299 1307 SETBLTYPE(sl, SUN_SL_ID);
1300 1308 }
1301 1309
1302 1310 static int
1303 1311 interpret_cipso_tagtype1(const uchar_t *opt)
1304 1312 {
1305 1313 int i, taglen, ishigh;
1306 1314 bslabel_t sl;
1307 1315 char line[CIPSO_GENERIC_ARRAY_LEN], *ptr;
1308 1316
1309 1317 taglen = opt[1];
1310 1318 if (taglen < TSOL_TT1_MIN_LENGTH ||
1311 1319 taglen > TSOL_TT1_MAX_LENGTH)
1312 1320 return (taglen);
1313 1321
1314 1322 (void) snprintf(get_line(0, 0), get_line_remain(),
1315 1323 "Tag Type = %d, Tag Length = %d", opt[0], opt[1]);
1316 1324 (void) snprintf(get_line(0, 0), get_line_remain(),
1317 1325 "Sensitivity Level = 0x%02x", opt[3]);
1318 1326 ptr = line;
1319 1327 for (i = 0; i < taglen - TSOL_TT1_MIN_LENGTH; i++) {
1320 1328 (void) snprintf(ptr, sizeof (line) - (ptr - line), "%02x",
1321 1329 opt[TSOL_TT1_MIN_LENGTH + i]);
1322 1330 ptr = strchr(ptr, 0);
1323 1331 }
1324 1332 if (i != 0) {
1325 1333 (void) snprintf(get_line(0, 0), get_line_remain(),
1326 1334 "Categories = ");
1327 1335 (void) snprintf(get_line(0, 0), get_line_remain(), "\t%s",
1328 1336 line);
1329 1337 } else {
1330 1338 (void) snprintf(get_line(0, 0), get_line_remain(),
1331 1339 "Categories = None");
1332 1340 }
1333 1341 cipso2sl(opt, &sl, &ishigh);
1334 1342 if (is_system_labeled()) {
1335 1343 if (bsltos(&sl, &plabel, ALABEL_MAXLEN,
1336 1344 LONG_CLASSIFICATION|LONG_WORDS|VIEW_INTERNAL) < 0) {
1337 1345 (void) snprintf(get_line(0, 0), get_line_remain(),
1338 1346 "The Sensitivity Level and Categories can't be "
1339 1347 "mapped to a valid SL");
1340 1348 } else {
1341 1349 (void) snprintf(get_line(0, 0), get_line_remain(),
1342 1350 "The Sensitivity Level and Categories are mapped "
1343 1351 "to the SL:");
1344 1352 (void) snprintf(get_line(0, 0), get_line_remain(),
1345 1353 "\t%s", ascii_label);
1346 1354 }
1347 1355 }
1348 1356 return (taglen);
1349 1357 }
1350 1358
1351 1359 /*
1352 1360 * The following struct definition #define's are copied from TS1.x. They are
1353 1361 * not used here (except TTYPE_3_MAX_TOKENS), but included as a reference for
1354 1362 * the tag type 3 packet format.
1355 1363 */
1356 1364 #define TTYPE_3_MAX_TOKENS 7
1357 1365
1358 1366 /*
1359 1367 * Display CIPSO tag type 3 which is defined by MAXSIX.
1360 1368 */
1361 1369 static int
1362 1370 interpret_cipso_tagtype3(const uchar_t *opt)
1363 1371 {
1364 1372 uchar_t tagtype;
1365 1373 int index, numtokens, taglen;
1366 1374 uint16_t mask;
1367 1375 uint32_t token;
1368 1376 static const char *name[] = {
1369 1377 "SL",
1370 1378 "NCAV",
1371 1379 "INTEG",
1372 1380 "SID",
1373 1381 "undefined",
1374 1382 "undefined",
1375 1383 "IL",
1376 1384 "PRIVS",
1377 1385 "LUID",
1378 1386 "PID",
1379 1387 "IDS",
1380 1388 "ACL"
1381 1389 };
1382 1390
1383 1391 tagtype = *opt++;
1384 1392 (void) memcpy(&mask, opt + 3, sizeof (mask));
1385 1393 (void) snprintf(get_line(0, 0), get_line_remain(),
1386 1394 "Tag Type = %d (MAXSIX)", tagtype);
1387 1395 (void) snprintf(get_line(0, 0), get_line_remain(),
1388 1396 "Generation = 0x%02x%02x%02x, Mask = 0x%04x", opt[0], opt[1],
1389 1397 opt[2], mask);
1390 1398 opt += 3 + sizeof (mask);
1391 1399
1392 1400 /*
1393 1401 * Display tokens
1394 1402 */
1395 1403 numtokens = 0;
1396 1404 index = 0;
1397 1405 while (mask != 0 && numtokens < TTYPE_3_MAX_TOKENS) {
1398 1406 if (mask & 0x0001) {
1399 1407 (void) memcpy(&token, opt, sizeof (token));
1400 1408 opt += sizeof (token);
1401 1409 (void) snprintf(get_line(0, 0), get_line_remain(),
1402 1410 "Attribute = %s, Token = 0x%08x",
1403 1411 index < sizeof (name) / sizeof (*name) ?
1404 1412 name[index] : "unknown", token);
1405 1413 numtokens++;
1406 1414 }
1407 1415 mask = mask >> 1;
1408 1416 index++;
1409 1417 }
1410 1418
1411 1419 taglen = 6 + numtokens * 4;
1412 1420 return (taglen);
1413 1421 }
1414 1422
1415 1423 static void
1416 1424 print_cipso(const uchar_t *opt)
1417 1425 {
1418 1426 int optlen, taglen, tagnum;
1419 1427 uint32_t doi;
1420 1428 char line[CIPSO_GENERIC_ARRAY_LEN];
1421 1429 char *oldnest;
1422 1430
1423 1431 optlen = opt[1];
1424 1432 if (optlen < TSOL_CIPSO_MIN_LENGTH || optlen > TSOL_CIPSO_MAX_LENGTH)
1425 1433 return;
1426 1434
1427 1435 oldnest = prot_nest_prefix;
1428 1436 prot_nest_prefix = prot_prefix;
1429 1437 show_header("CIPSO: ", "Common IP Security Option", 0);
1430 1438 show_space();
1431 1439
1432 1440 /*
1433 1441 * Display CIPSO Header
1434 1442 */
1435 1443 (void) snprintf(get_line(0, 0), get_line_remain(),
1436 1444 "Type = CIPSO (%d), Length = %d", opt[0], opt[1]);
1437 1445 (void) memcpy(&doi, opt + 2, sizeof (doi));
1438 1446 (void) snprintf(get_line(0, 0), get_line_remain(),
1439 1447 "Domain of Interpretation = %u", (unsigned)ntohl(doi));
1440 1448
1441 1449 if (opt[1] == TSOL_CIPSO_MIN_LENGTH) { /* no tags */
1442 1450 show_space();
1443 1451 prot_prefix = prot_nest_prefix;
1444 1452 prot_nest_prefix = oldnest;
1445 1453 return;
1446 1454 }
1447 1455 optlen -= TSOL_CIPSO_MIN_LENGTH;
1448 1456 opt += TSOL_CIPSO_MIN_LENGTH;
1449 1457
1450 1458 /*
1451 1459 * Display Each Tag
1452 1460 */
1453 1461 tagnum = 1;
1454 1462 while (optlen >= TSOL_TT1_MIN_LENGTH) {
1455 1463 (void) snprintf(line, sizeof (line), "Tag# %d", tagnum);
1456 1464 show_header("CIPSO: ", line, 0);
1457 1465 /*
1458 1466 * We handle tag type 1 and 3 only. Note, tag type 3
1459 1467 * is MAXSIX defined.
1460 1468 */
1461 1469 switch (opt[0]) {
1462 1470 case 1:
1463 1471 taglen = interpret_cipso_tagtype1(opt);
1464 1472 break;
1465 1473 case 3:
1466 1474 taglen = interpret_cipso_tagtype3(opt);
1467 1475 break;
1468 1476 default:
1469 1477 (void) snprintf(get_line(0, 0), get_line_remain(),
1470 1478 "Unknown Tag Type %d", opt[0]);
1471 1479 show_space();
1472 1480 prot_prefix = prot_nest_prefix;
1473 1481 prot_nest_prefix = oldnest;
1474 1482 return;
1475 1483 }
1476 1484
1477 1485 /*
1478 1486 * Move to the next tag
1479 1487 */
1480 1488 if (taglen <= 0)
1481 1489 break;
1482 1490 optlen -= taglen;
1483 1491 opt += taglen;
1484 1492 tagnum++;
1485 1493 }
1486 1494 show_space();
1487 1495 prot_prefix = prot_nest_prefix;
1488 1496 prot_nest_prefix = oldnest;
1489 1497 }
↓ open down ↓ |
1000 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX