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