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, nd_ipv6 *dst,
48            const struct ip6_hdr *ip6)
49{
50	const u_char *cp;
51	u_int advance;
52	u_int nh;
53	const void *dst_addr;
54	const struct ip6_rthdr *dp;
55	const struct ip6_rthdr0 *dp0;
56	const struct ip6_srh *srh;
57	const u_char *p;
58	int i, len;
59
60	cp = (const u_char *)ip6;
61	advance = sizeof(struct ip6_hdr);
62	nh = GET_U_1(ip6->ip6_nxt);
63	dst_addr = (const void *)ip6->ip6_dst;
64
65	while (cp < ndo->ndo_snapend) {
66		cp += advance;
67
68		switch (nh) {
69
70		case IPPROTO_HOPOPTS:
71		case IPPROTO_DSTOPTS:
72		case IPPROTO_MOBILITY_OLD:
73		case IPPROTO_MOBILITY:
74			/*
75			 * These have a header length byte, following
76			 * the next header byte, giving the length of
77			 * the header, in units of 8 octets, excluding
78			 * the first 8 octets.
79			 */
80			advance = (GET_U_1(cp + 1) + 1) << 3;
81			nh = GET_U_1(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			advance = sizeof(struct ip6_frag);
91			nh = GET_U_1(cp);
92			break;
93
94		case IPPROTO_ROUTING:
95			/*
96			 * OK, we found it.
97			 */
98			dp = (const struct ip6_rthdr *)cp;
99			ND_TCHECK_SIZE(dp);
100			len = GET_U_1(dp->ip6r_len);
101			switch (GET_U_1(dp->ip6r_type)) {
102
103			case IPV6_RTHDR_TYPE_0:
104			case IPV6_RTHDR_TYPE_2:		/* Mobile IPv6 ID-20 */
105				dp0 = (const struct ip6_rthdr0 *)dp;
106				if (len % 2 == 1)
107					goto trunc;
108				len >>= 1;
109				p = (const u_char *) dp0->ip6r0_addr;
110				for (i = 0; i < len; i++) {
111					ND_TCHECK_16(p);
112					dst_addr = (const void *)p;
113					p += 16;
114				}
115				break;
116			case IPV6_RTHDR_TYPE_4:
117				/* IPv6 Segment Routing Header (SRH) */
118				srh = (const struct ip6_srh *)dp;
119				if (len % 2 == 1)
120					goto trunc;
121				p = (const u_char *) srh->srh_segments;
122				/*
123				 * The list of segments are encoded in the reverse order.
124				 * Accordingly, the final DA is encoded in srh_segments[0]
125				 */
126				ND_TCHECK_16(p);
127				dst_addr = (const void *)p;
128				break;
129
130			default:
131				break;
132			}
133
134			/*
135			 * Only one routing header to a customer.
136			 */
137			goto done;
138
139		case IPPROTO_AH:
140		case IPPROTO_ESP:
141		case IPPROTO_IPCOMP:
142		default:
143			/*
144			 * AH and ESP are, in the RFCs that describe them,
145			 * described as being "viewed as an end-to-end
146			 * payload" "in the IPv6 context, so that they
147			 * "should appear after hop-by-hop, routing, and
148			 * fragmentation extension headers".  We assume
149			 * that's the case, and stop as soon as we see
150			 * one.  (We can't handle an ESP header in
151			 * the general case anyway, as its length depends
152			 * on the encryption algorithm.)
153			 *
154			 * IPComp is also "viewed as an end-to-end
155			 * payload" "in the IPv6 context".
156			 *
157			 * All other protocols are assumed to be the final
158			 * protocol.
159			 */
160			goto done;
161		}
162	}
163
164done:
165trunc:
166	GET_CPY_BYTES(dst, dst_addr, sizeof(nd_ipv6));
167}
168
169/*
170 * Compute a V6-style checksum by building a pseudoheader.
171 */
172uint16_t
173nextproto6_cksum(netdissect_options *ndo,
174                 const struct ip6_hdr *ip6, const uint8_t *data,
175		 u_int len, u_int covlen, uint8_t next_proto)
176{
177        struct {
178                nd_ipv6 ph_src;
179                nd_ipv6 ph_dst;
180                uint32_t       ph_len;
181                uint8_t        ph_zero[3];
182                uint8_t        ph_nxt;
183        } ph;
184        struct cksum_vec vec[2];
185        u_int nh;
186
187        /* pseudo-header */
188        memset(&ph, 0, sizeof(ph));
189        GET_CPY_BYTES(&ph.ph_src, ip6->ip6_src, sizeof(nd_ipv6));
190        nh = GET_U_1(ip6->ip6_nxt);
191        switch (nh) {
192
193        case IPPROTO_HOPOPTS:
194        case IPPROTO_DSTOPTS:
195        case IPPROTO_MOBILITY_OLD:
196        case IPPROTO_MOBILITY:
197        case IPPROTO_FRAGMENT:
198        case IPPROTO_ROUTING:
199                /*
200                 * The next header is either a routing header or a header
201                 * after which there might be a routing header, so scan
202                 * for a routing header.
203                 */
204                ip6_finddst(ndo, &ph.ph_dst, ip6);
205                break;
206
207        default:
208                GET_CPY_BYTES(&ph.ph_dst, ip6->ip6_dst, sizeof(nd_ipv6));
209                break;
210        }
211        ph.ph_len = htonl(len);
212        ph.ph_nxt = next_proto;
213
214        vec[0].ptr = (const uint8_t *)(void *)&ph;
215        vec[0].len = sizeof(ph);
216        vec[1].ptr = data;
217        vec[1].len = covlen;
218
219        return in_cksum(vec, 2);
220}
221
222/*
223 * print an IP6 datagram.
224 */
225void
226ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
227{
228	const struct ip6_hdr *ip6;
229	int advance;
230	u_int len;
231	u_int total_advance;
232	const u_char *cp;
233	uint32_t payload_len;
234	uint8_t ph, nh;
235	int fragmented = 0;
236	u_int flow;
237	int found_extension_header;
238	int found_jumbo;
239	int found_hbh;
240
241	ndo->ndo_protocol = "ip6";
242	ip6 = (const struct ip6_hdr *)bp;
243
244	ND_TCHECK_SIZE(ip6);
245	if (length < sizeof (struct ip6_hdr)) {
246		ND_PRINT("truncated-ip6 %u", length);
247		return;
248	}
249
250	if (!ndo->ndo_eflag)
251	    ND_PRINT("IP6 ");
252
253	if (IP6_VERSION(ip6) != 6) {
254	  ND_PRINT("version error: %u != 6", IP6_VERSION(ip6));
255	  return;
256	}
257
258	payload_len = GET_BE_U_2(ip6->ip6_plen);
259	/*
260	 * RFC 1883 says:
261	 *
262	 * The Payload Length field in the IPv6 header must be set to zero
263	 * in every packet that carries the Jumbo Payload option.  If a
264	 * packet is received with a valid Jumbo Payload option present and
265	 * a non-zero IPv6 Payload Length field, an ICMP Parameter Problem
266	 * message, Code 0, should be sent to the packet's source, pointing
267	 * to the Option Type field of the Jumbo Payload option.
268	 *
269	 * Later versions of the IPv6 spec don't discuss the Jumbo Payload
270	 * option.
271	 *
272	 * If the payload length is 0, we temporarily just set the total
273	 * length to the remaining data in the packet (which, for Ethernet,
274	 * could include frame padding, but if it's a Jumbo Payload frame,
275	 * it shouldn't even be sendable over Ethernet, so we don't worry
276	 * about that), so we can process the extension headers in order
277	 * to *find* a Jumbo Payload hop-by-hop option and, when we've
278	 * processed all the extension headers, check whether we found
279	 * a Jumbo Payload option, and fail if we haven't.
280	 */
281	if (payload_len != 0) {
282		len = payload_len + sizeof(struct ip6_hdr);
283		if (length < len)
284			ND_PRINT("truncated-ip6 - %u bytes missing!",
285				len - length);
286	} else
287		len = length + sizeof(struct ip6_hdr);
288
289	ph = 255;
290	nh = GET_U_1(ip6->ip6_nxt);
291	if (ndo->ndo_vflag) {
292	    flow = GET_BE_U_4(ip6->ip6_flow);
293	    ND_PRINT("(");
294	    /* RFC 2460 */
295	    if (flow & 0x0ff00000)
296	        ND_PRINT("class 0x%02x, ", (flow & 0x0ff00000) >> 20);
297	    if (flow & 0x000fffff)
298	        ND_PRINT("flowlabel 0x%05x, ", flow & 0x000fffff);
299
300	    ND_PRINT("hlim %u, next-header %s (%u) payload length: %u) ",
301	                 GET_U_1(ip6->ip6_hlim),
302	                 tok2str(ipproto_values,"unknown",nh),
303	                 nh,
304	                 payload_len);
305	}
306
307	/*
308	 * Cut off the snapshot length to the end of the IP payload.
309	 */
310	if (!nd_push_snaplen(ndo, bp, len)) {
311		(*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
312			"%s: can't push snaplen on buffer stack", __func__);
313	}
314
315	cp = (const u_char *)ip6;
316	advance = sizeof(struct ip6_hdr);
317	total_advance = 0;
318	/* Process extension headers */
319	found_extension_header = 0;
320	found_jumbo = 0;
321	found_hbh = 0;
322	while (cp < ndo->ndo_snapend && advance > 0) {
323		if (len < (u_int)advance)
324			goto trunc;
325		cp += advance;
326		len -= advance;
327		total_advance += advance;
328
329		if (cp == (const u_char *)(ip6 + 1) &&
330		    nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
331		    nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
332			ND_PRINT("%s > %s: ", GET_IP6ADDR_STRING(ip6->ip6_src),
333				     GET_IP6ADDR_STRING(ip6->ip6_dst));
334		}
335
336		switch (nh) {
337
338		case IPPROTO_HOPOPTS:
339			/*
340			 * The Hop-by-Hop Options header, when present,
341			 * must immediately follow the IPv6 header (RFC 8200)
342			 */
343			if (found_hbh == 1) {
344				ND_PRINT("[The Hop-by-Hop Options header was already found]");
345				nd_print_invalid(ndo);
346				return;
347			}
348			if (ph != 255) {
349				ND_PRINT("[The Hop-by-Hop Options header don't follow the IPv6 header]");
350				nd_print_invalid(ndo);
351				return;
352			}
353			advance = hbhopt_process(ndo, cp, &found_jumbo, &payload_len);
354			if (payload_len == 0 && found_jumbo == 0) {
355				ND_PRINT("[No valid Jumbo Payload Hop-by-Hop option found]");
356				nd_print_invalid(ndo);
357				return;
358			}
359			if (advance < 0) {
360				nd_pop_packet_info(ndo);
361				return;
362			}
363			found_extension_header = 1;
364			found_hbh = 1;
365			nh = GET_U_1(cp);
366			break;
367
368		case IPPROTO_DSTOPTS:
369			advance = dstopt_process(ndo, cp);
370			if (advance < 0) {
371				nd_pop_packet_info(ndo);
372				return;
373			}
374			found_extension_header = 1;
375			nh = GET_U_1(cp);
376			break;
377
378		case IPPROTO_FRAGMENT:
379			advance = frag6_print(ndo, cp, (const u_char *)ip6);
380			if (advance < 0 || ndo->ndo_snapend <= cp + advance) {
381				nd_pop_packet_info(ndo);
382				return;
383			}
384			found_extension_header = 1;
385			nh = GET_U_1(cp);
386			fragmented = 1;
387			break;
388
389		case IPPROTO_MOBILITY_OLD:
390		case IPPROTO_MOBILITY:
391			/*
392			 * XXX - we don't use "advance"; RFC 3775 says that
393			 * the next header field in a mobility header
394			 * should be IPPROTO_NONE, but speaks of
395			 * the possibility of a future extension in
396			 * which payload can be piggybacked atop a
397			 * mobility header.
398			 */
399			advance = mobility_print(ndo, cp, (const u_char *)ip6);
400			if (advance < 0) {
401				nd_pop_packet_info(ndo);
402				return;
403			}
404			found_extension_header = 1;
405			nh = GET_U_1(cp);
406			nd_pop_packet_info(ndo);
407			return;
408
409		case IPPROTO_ROUTING:
410			ND_TCHECK_1(cp);
411			advance = rt6_print(ndo, cp, (const u_char *)ip6);
412			if (advance < 0) {
413				nd_pop_packet_info(ndo);
414				return;
415			}
416			found_extension_header = 1;
417			nh = GET_U_1(cp);
418			break;
419
420		default:
421			/*
422			 * Not an extension header; hand off to the
423			 * IP protocol demuxer.
424			 */
425			if (found_jumbo) {
426				/*
427				 * We saw a Jumbo Payload option.
428				 * Set the length to the payload length
429				 * plus the IPv6 header length, and
430				 * change the snapshot length accordingly.
431				 *
432				 * But make sure it's not shorter than
433				 * the total number of bytes we've
434				 * processed so far.
435				 */
436				len = payload_len + sizeof(struct ip6_hdr);
437				if (len < total_advance)
438					goto trunc;
439				if (length < len)
440					ND_PRINT("truncated-ip6 - %u bytes missing!",
441						len - length);
442				nd_change_snaplen(ndo, bp, len);
443
444				/*
445				 * Now subtract the length of the IPv6
446				 * header plus extension headers to get
447				 * the payload length.
448				 */
449				len -= total_advance;
450			} else {
451				/*
452				 * We didn't see a Jumbo Payload option;
453				 * was the payload length zero?
454				 */
455				if (payload_len == 0) {
456					/*
457					 * Yes.  If we found an extension
458					 * header, treat that as a truncated
459					 * packet header, as there was
460					 * no payload to contain an
461					 * extension header.
462					 */
463					if (found_extension_header)
464						goto trunc;
465
466					/*
467					 * OK, we didn't see any extension
468					 * header, but that means we have
469					 * no payload, so set the length
470					 * to the IPv6 header length,
471					 * and change the snapshot length
472					 * accordingly.
473					 */
474					len = sizeof(struct ip6_hdr);
475					nd_change_snaplen(ndo, bp, len);
476
477					/*
478					 * Now subtract the length of
479					 * the IPv6 header plus extension
480					 * headers (there weren't any, so
481					 * that's just the IPv6 header
482					 * length) to get the payload length.
483					 */
484					len -= total_advance;
485				}
486			}
487			ip_demux_print(ndo, cp, len, 6, fragmented,
488				       GET_U_1(ip6->ip6_hlim), nh, bp);
489			nd_pop_packet_info(ndo);
490			return;
491		}
492		ph = nh;
493
494		/* ndo_protocol reassignment after xxx_print() calls */
495		ndo->ndo_protocol = "ip6";
496	}
497
498	nd_pop_packet_info(ndo);
499	return;
500trunc:
501	nd_print_trunc(ndo);
502}
503