]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-ip6.c
Import 1.14.3
[FreeBSD/FreeBSD.git] / contrib / 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 #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  */
46 static void
47 ip6_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
154 done:
155 trunc:
156         UNALIGNED_MEMCPY(dst, dst_addr, sizeof(struct in6_addr));
157 }
158
159 /*
160  * Compute a V6-style checksum by building a pseudoheader.
161  */
162 int
163 nextproto6_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  */
213 void
214 ip6_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;
410 trunc:
411         ND_PRINT((ndo, "[|ip6]"));
412 }