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