]> The Tcpdump Group git mirrors - tcpdump/blob - print-ip6.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / print-ip6.c
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
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
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
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 * or the end of the data in which it's contained, whichever
306 * comes first.
307 */
308 if (!nd_push_snaplen(ndo, bp, ND_MIN(length, len))) {
309 (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
310 "%s: can't push snaplen on buffer stack", __func__);
311 }
312
313 cp = (const u_char *)ip6;
314 advance = sizeof(struct ip6_hdr);
315 total_advance = 0;
316 /* Process extension headers */
317 found_extension_header = 0;
318 found_jumbo = 0;
319 found_hbh = 0;
320 while (cp < ndo->ndo_snapend && advance > 0) {
321 if (len < (u_int)advance)
322 goto trunc;
323 cp += advance;
324 len -= advance;
325 total_advance += advance;
326
327 if (cp == (const u_char *)(ip6 + 1) &&
328 nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
329 nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
330 ND_PRINT("%s > %s: ", GET_IP6ADDR_STRING(ip6->ip6_src),
331 GET_IP6ADDR_STRING(ip6->ip6_dst));
332 }
333
334 switch (nh) {
335
336 case IPPROTO_HOPOPTS:
337 /*
338 * The Hop-by-Hop Options header, when present,
339 * must immediately follow the IPv6 header (RFC 8200)
340 */
341 if (found_hbh == 1) {
342 ND_PRINT("[The Hop-by-Hop Options header was already found]");
343 nd_print_invalid(ndo);
344 return;
345 }
346 if (ph != 255) {
347 ND_PRINT("[The Hop-by-Hop Options header don't follow the IPv6 header]");
348 nd_print_invalid(ndo);
349 return;
350 }
351 advance = hbhopt_process(ndo, cp, &found_jumbo, &payload_len);
352 if (payload_len == 0 && found_jumbo == 0) {
353 ND_PRINT("[No valid Jumbo Payload Hop-by-Hop option found]");
354 nd_print_invalid(ndo);
355 return;
356 }
357 if (advance < 0) {
358 nd_pop_packet_info(ndo);
359 return;
360 }
361 found_extension_header = 1;
362 found_hbh = 1;
363 nh = GET_U_1(cp);
364 break;
365
366 case IPPROTO_DSTOPTS:
367 advance = dstopt_process(ndo, cp);
368 if (advance < 0) {
369 nd_pop_packet_info(ndo);
370 return;
371 }
372 found_extension_header = 1;
373 nh = GET_U_1(cp);
374 break;
375
376 case IPPROTO_FRAGMENT:
377 advance = frag6_print(ndo, cp, (const u_char *)ip6);
378 if (advance < 0 || ndo->ndo_snapend <= cp + advance) {
379 nd_pop_packet_info(ndo);
380 return;
381 }
382 found_extension_header = 1;
383 nh = GET_U_1(cp);
384 fragmented = 1;
385 break;
386
387 case IPPROTO_MOBILITY_OLD:
388 case IPPROTO_MOBILITY:
389 /*
390 * RFC 3775 says that
391 * the next header field in a mobility header
392 * should be IPPROTO_NONE, but speaks of
393 * the possibility of a future extension in
394 * which payload can be piggybacked atop a
395 * mobility header.
396 */
397 advance = mobility_print(ndo, cp, (const u_char *)ip6);
398 if (advance < 0) {
399 nd_pop_packet_info(ndo);
400 return;
401 }
402 found_extension_header = 1;
403 nh = GET_U_1(cp);
404 nd_pop_packet_info(ndo);
405 return;
406
407 case IPPROTO_ROUTING:
408 ND_TCHECK_1(cp);
409 advance = rt6_print(ndo, cp, (const u_char *)ip6);
410 if (advance < 0) {
411 nd_pop_packet_info(ndo);
412 return;
413 }
414 found_extension_header = 1;
415 nh = GET_U_1(cp);
416 break;
417
418 default:
419 /*
420 * Not an extension header; hand off to the
421 * IP protocol demuxer.
422 */
423 if (found_jumbo) {
424 /*
425 * We saw a Jumbo Payload option.
426 * Set the length to the payload length
427 * plus the IPv6 header length, and
428 * change the snapshot length accordingly.
429 *
430 * But make sure it's not shorter than
431 * the total number of bytes we've
432 * processed so far.
433 */
434 len = payload_len + sizeof(struct ip6_hdr);
435 if (len < total_advance)
436 goto trunc;
437 if (len > length) {
438 ND_PRINT("[header+payload length %u > length %u]",
439 len, length);
440 nd_print_invalid(ndo);
441 ND_PRINT(" ");
442 }
443 nd_change_snaplen(ndo, bp, len);
444
445 /*
446 * Now subtract the length of the IPv6
447 * header plus extension headers to get
448 * the payload length.
449 */
450 len -= total_advance;
451 } else {
452 /*
453 * We didn't see a Jumbo Payload option;
454 * was the payload length zero?
455 */
456 if (payload_len == 0) {
457 /*
458 * Yes. If we found an extension
459 * header, treat that as a truncated
460 * packet header, as there was
461 * no payload to contain an
462 * extension header.
463 */
464 if (found_extension_header)
465 goto trunc;
466
467 /*
468 * OK, we didn't see any extension
469 * header, but that means we have
470 * no payload, so set the length
471 * to the IPv6 header length,
472 * and change the snapshot length
473 * accordingly.
474 */
475 len = sizeof(struct ip6_hdr);
476 nd_change_snaplen(ndo, bp, len);
477
478 /*
479 * Now subtract the length of
480 * the IPv6 header plus extension
481 * headers (there weren't any, so
482 * that's just the IPv6 header
483 * length) to get the payload length.
484 */
485 len -= total_advance;
486 }
487 }
488 ip_demux_print(ndo, cp, len, 6, fragmented,
489 GET_U_1(ip6->ip6_hlim), nh, bp);
490 nd_pop_packet_info(ndo);
491 return;
492 }
493 ph = nh;
494
495 /* ndo_protocol reassignment after xxx_print() calls */
496 ndo->ndo_protocol = "ip6";
497 }
498
499 nd_pop_packet_info(ndo);
500 return;
501 trunc:
502 nd_print_trunc(ndo);
503 return;
504
505 invalid:
506 nd_print_invalid(ndo);
507 }