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