xref: /netbsd-src/external/bsd/tcpdump/dist/print-ip6.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 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 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: print-ip6.c,v 1.8 2017/09/08 14:01:13 christos Exp $");
25 #endif
26 
27 /* \summary: IPv6 printer */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <netdissect-stdinc.h>
34 
35 #include <string.h>
36 
37 #include "netdissect.h"
38 #include "addrtoname.h"
39 #include "extract.h"
40 
41 #include "ip6.h"
42 #include "ipproto.h"
43 
44 /*
45  * If routing headers are presend and valid, set dst to the final destination.
46  * Otherwise, set it to the IPv6 destination.
47  *
48  * This is used for UDP and TCP pseudo-header in the checksum
49  * calculation.
50  */
51 static void
52 ip6_finddst(netdissect_options *ndo, struct in6_addr *dst,
53             const struct ip6_hdr *ip6)
54 {
55 	const u_char *cp;
56 	int advance;
57 	u_int nh;
58 	const struct in6_addr *dst_addr;
59 	const struct ip6_rthdr *dp;
60 	const struct ip6_rthdr0 *dp0;
61 	const struct in6_addr *addr;
62 	int i, len;
63 
64 	cp = (const u_char *)ip6;
65 	advance = sizeof(struct ip6_hdr);
66 	nh = ip6->ip6_nxt;
67 	dst_addr = &ip6->ip6_dst;
68 
69 	while (cp < ndo->ndo_snapend) {
70 		cp += advance;
71 
72 		switch (nh) {
73 
74 		case IPPROTO_HOPOPTS:
75 		case IPPROTO_DSTOPTS:
76 		case IPPROTO_MOBILITY_OLD:
77 		case IPPROTO_MOBILITY:
78 			/*
79 			 * These have a header length byte, following
80 			 * the next header byte, giving the length of
81 			 * the header, in units of 8 octets, excluding
82 			 * the first 8 octets.
83 			 */
84 			ND_TCHECK2(*cp, 2);
85 			advance = (int)((*(cp + 1) + 1) << 3);
86 			nh = *cp;
87 			break;
88 
89 		case IPPROTO_FRAGMENT:
90 			/*
91 			 * The byte following the next header byte is
92 			 * marked as reserved, and the header is always
93 			 * the same size.
94 			 */
95 			ND_TCHECK2(*cp, 1);
96 			advance = sizeof(struct ip6_frag);
97 			nh = *cp;
98 			break;
99 
100 		case IPPROTO_ROUTING:
101 			/*
102 			 * OK, we found it.
103 			 */
104 			dp = (const struct ip6_rthdr *)cp;
105 			ND_TCHECK(*dp);
106 			len = dp->ip6r_len;
107 			switch (dp->ip6r_type) {
108 
109 			case IPV6_RTHDR_TYPE_0:
110 			case IPV6_RTHDR_TYPE_2:		/* Mobile IPv6 ID-20 */
111 				dp0 = (const struct ip6_rthdr0 *)dp;
112 				if (len % 2 == 1)
113 					goto trunc;
114 				len >>= 1;
115 				addr = &dp0->ip6r0_addr[0];
116 				for (i = 0; i < len; i++) {
117 					if ((const u_char *)(addr + 1) > ndo->ndo_snapend)
118 						goto trunc;
119 
120 					dst_addr = addr;
121 					addr++;
122 				}
123 				break;
124 
125 			default:
126 				break;
127 			}
128 
129 			/*
130 			 * Only one routing header to a customer.
131 			 */
132 			goto done;
133 
134 		case IPPROTO_AH:
135 		case IPPROTO_ESP:
136 		case IPPROTO_IPCOMP:
137 		default:
138 			/*
139 			 * AH and ESP are, in the RFCs that describe them,
140 			 * described as being "viewed as an end-to-end
141 			 * payload" "in the IPv6 context, so that they
142 			 * "should appear after hop-by-hop, routing, and
143 			 * fragmentation extension headers".  We assume
144 			 * that's the case, and stop as soon as we see
145 			 * one.  (We can't handle an ESP header in
146 			 * the general case anyway, as its length depends
147 			 * on the encryption algorithm.)
148 			 *
149 			 * IPComp is also "viewed as an end-to-end
150 			 * payload" "in the IPv6 context".
151 			 *
152 			 * All other protocols are assumed to be the final
153 			 * protocol.
154 			 */
155 			goto done;
156 		}
157 	}
158 
159 done:
160 trunc:
161 	UNALIGNED_MEMCPY(dst, dst_addr, sizeof(struct in6_addr));
162 }
163 
164 /*
165  * Compute a V6-style checksum by building a pseudoheader.
166  */
167 int
168 nextproto6_cksum(netdissect_options *ndo,
169                  const struct ip6_hdr *ip6, const uint8_t *data,
170 		 u_int len, u_int covlen, u_int next_proto)
171 {
172         struct {
173                 struct in6_addr ph_src;
174                 struct in6_addr ph_dst;
175                 uint32_t       ph_len;
176                 uint8_t        ph_zero[3];
177                 uint8_t        ph_nxt;
178         } ph;
179         struct cksum_vec vec[2];
180 
181         /* pseudo-header */
182         memset(&ph, 0, sizeof(ph));
183         UNALIGNED_MEMCPY(&ph.ph_src, &ip6->ip6_src, sizeof (struct in6_addr));
184         switch (ip6->ip6_nxt) {
185 
186         case IPPROTO_HOPOPTS:
187         case IPPROTO_DSTOPTS:
188         case IPPROTO_MOBILITY_OLD:
189         case IPPROTO_MOBILITY:
190         case IPPROTO_FRAGMENT:
191         case IPPROTO_ROUTING:
192                 /*
193                  * The next header is either a routing header or a header
194                  * after which there might be a routing header, so scan
195                  * for a routing header.
196                  */
197                 ip6_finddst(ndo, &ph.ph_dst, ip6);
198                 break;
199 
200         default:
201                 UNALIGNED_MEMCPY(&ph.ph_dst, &ip6->ip6_dst, sizeof (struct in6_addr));
202                 break;
203         }
204         ph.ph_len = htonl(len);
205         ph.ph_nxt = next_proto;
206 
207         vec[0].ptr = (const uint8_t *)(void *)&ph;
208         vec[0].len = sizeof(ph);
209         vec[1].ptr = data;
210         vec[1].len = covlen;
211 
212         return in_cksum(vec, 2);
213 }
214 
215 /*
216  * print an IP6 datagram.
217  */
218 void
219 ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
220 {
221 	register const struct ip6_hdr *ip6;
222 	register int advance;
223 	u_int len;
224 	const u_char *ipend;
225 	register const u_char *cp;
226 	register u_int payload_len;
227 	int nh;
228 	int fragmented = 0;
229 	u_int flow;
230 
231 	ip6 = (const struct ip6_hdr *)bp;
232 
233 	ND_TCHECK(*ip6);
234 	if (length < sizeof (struct ip6_hdr)) {
235 		ND_PRINT((ndo, "truncated-ip6 %u", length));
236 		return;
237 	}
238 
239         if (!ndo->ndo_eflag)
240             ND_PRINT((ndo, "IP6 "));
241 
242 	if (IP6_VERSION(ip6) != 6) {
243           ND_PRINT((ndo,"version error: %u != 6", IP6_VERSION(ip6)));
244           return;
245 	}
246 
247 	payload_len = EXTRACT_16BITS(&ip6->ip6_plen);
248 	len = payload_len + sizeof(struct ip6_hdr);
249 	if (length < len)
250 		ND_PRINT((ndo, "truncated-ip6 - %u bytes missing!",
251 			len - length));
252 
253         if (ndo->ndo_vflag) {
254             flow = EXTRACT_32BITS(&ip6->ip6_flow);
255             ND_PRINT((ndo, "("));
256 #if 0
257             /* rfc1883 */
258             if (flow & 0x0f000000)
259 		ND_PRINT((ndo, "pri 0x%02x, ", (flow & 0x0f000000) >> 24));
260             if (flow & 0x00ffffff)
261 		ND_PRINT((ndo, "flowlabel 0x%06x, ", flow & 0x00ffffff));
262 #else
263             /* RFC 2460 */
264             if (flow & 0x0ff00000)
265 		ND_PRINT((ndo, "class 0x%02x, ", (flow & 0x0ff00000) >> 20));
266             if (flow & 0x000fffff)
267 		ND_PRINT((ndo, "flowlabel 0x%05x, ", flow & 0x000fffff));
268 #endif
269 
270             ND_PRINT((ndo, "hlim %u, next-header %s (%u) payload length: %u) ",
271                          ip6->ip6_hlim,
272                          tok2str(ipproto_values,"unknown",ip6->ip6_nxt),
273                          ip6->ip6_nxt,
274                          payload_len));
275         }
276 
277 	/*
278 	 * Cut off the snapshot length to the end of the IP payload.
279 	 */
280 	ipend = bp + len;
281 	if (ipend < ndo->ndo_snapend)
282 		ndo->ndo_snapend = ipend;
283 
284 	cp = (const u_char *)ip6;
285 	advance = sizeof(struct ip6_hdr);
286 	nh = ip6->ip6_nxt;
287 	while (cp < ndo->ndo_snapend && advance > 0) {
288 		if (len < (u_int)advance)
289 			goto trunc;
290 		cp += advance;
291 		len -= advance;
292 
293 		if (cp == (const u_char *)(ip6 + 1) &&
294 		    nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
295 		    nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
296 			ND_PRINT((ndo, "%s > %s: ", ip6addr_string(ndo, &ip6->ip6_src),
297 				     ip6addr_string(ndo, &ip6->ip6_dst)));
298 		}
299 
300 		switch (nh) {
301 		case IPPROTO_HOPOPTS:
302 			advance = hbhopt_print(ndo, cp);
303 			if (advance < 0)
304 				return;
305 			nh = *cp;
306 			break;
307 		case IPPROTO_DSTOPTS:
308 			advance = dstopt_print(ndo, cp);
309 			if (advance < 0)
310 				return;
311 			nh = *cp;
312 			break;
313 		case IPPROTO_FRAGMENT:
314 			advance = frag6_print(ndo, cp, (const u_char *)ip6);
315 			if (advance < 0 || ndo->ndo_snapend <= cp + advance)
316 				return;
317 			nh = *cp;
318 			fragmented = 1;
319 			break;
320 
321 		case IPPROTO_MOBILITY_OLD:
322 		case IPPROTO_MOBILITY:
323 			/*
324 			 * XXX - we don't use "advance"; RFC 3775 says that
325 			 * the next header field in a mobility header
326 			 * should be IPPROTO_NONE, but speaks of
327 			 * the possiblity of a future extension in
328 			 * which payload can be piggybacked atop a
329 			 * mobility header.
330 			 */
331 			advance = mobility_print(ndo, cp, (const u_char *)ip6);
332 			if (advance < 0)
333 				return;
334 			nh = *cp;
335 			return;
336 		case IPPROTO_ROUTING:
337 			ND_TCHECK(*cp);
338 			advance = rt6_print(ndo, cp, (const u_char *)ip6);
339 			if (advance < 0)
340 				return;
341 			nh = *cp;
342 			break;
343 		case IPPROTO_SCTP:
344 			sctp_print(ndo, cp, (const u_char *)ip6, len);
345 			return;
346 		case IPPROTO_DCCP:
347 			dccp_print(ndo, cp, (const u_char *)ip6, len);
348 			return;
349 		case IPPROTO_TCP:
350 			tcp_print(ndo, cp, len, (const u_char *)ip6, fragmented);
351 			return;
352 		case IPPROTO_UDP:
353 			udp_print(ndo, cp, len, (const u_char *)ip6, fragmented);
354 			return;
355 		case IPPROTO_ICMPV6:
356 			icmp6_print(ndo, cp, len, (const u_char *)ip6, fragmented);
357 			return;
358 		case IPPROTO_AH:
359 			advance = ah_print(ndo, cp);
360 			if (advance < 0)
361 				return;
362 			nh = *cp;
363 			break;
364 		case IPPROTO_ESP:
365 		    {
366 			int enh, padlen;
367 			advance = esp_print(ndo, cp, len, (const u_char *)ip6, &enh, &padlen);
368 			if (advance < 0)
369 				return;
370 			nh = enh & 0xff;
371 			len -= padlen;
372 			break;
373 		    }
374 		case IPPROTO_IPCOMP:
375 		    {
376 			ipcomp_print(ndo, cp);
377 			/*
378 			 * Either this has decompressed the payload and
379 			 * printed it, in which case there's nothing more
380 			 * to do, or it hasn't, in which case there's
381 			 * nothing more to do.
382 			 */
383 			advance = -1;
384 			break;
385 		    }
386 
387 		case IPPROTO_PIM:
388 			pim_print(ndo, cp, len, (const u_char *)ip6);
389 			return;
390 
391 		case IPPROTO_OSPF:
392 			ospf6_print(ndo, cp, len);
393 			return;
394 
395 		case IPPROTO_IPV6:
396 			ip6_print(ndo, cp, len);
397 			return;
398 
399 		case IPPROTO_IPV4:
400 		        ip_print(ndo, cp, len);
401 			return;
402 
403                 case IPPROTO_PGM:
404                         pgm_print(ndo, cp, len, (const u_char *)ip6);
405                         return;
406 
407 		case IPPROTO_GRE:
408 			gre_print(ndo, cp, len);
409 			return;
410 
411 		case IPPROTO_RSVP:
412 			rsvp_print(ndo, cp, len);
413 			return;
414 
415 		case IPPROTO_NONE:
416 			ND_PRINT((ndo, "no next header"));
417 			return;
418 
419 		default:
420 			ND_PRINT((ndo, "ip-proto-%d %d", nh, len));
421 			return;
422 		}
423 	}
424 
425 	return;
426 trunc:
427 	ND_PRINT((ndo, "[|ip6]"));
428 }
429