Bring in efibootmgr(8) from FreeBSD.
[dragonfly.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                 if (len < (u_int)advance)
284                         goto trunc;
285                 cp += advance;
286                 len -= advance;
287
288                 if (cp == (const u_char *)(ip6 + 1) &&
289                     nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
290                     nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
291                         ND_PRINT((ndo, "%s > %s: ", ip6addr_string(ndo, &ip6->ip6_src),
292                                      ip6addr_string(ndo, &ip6->ip6_dst)));
293                 }
294
295                 switch (nh) {
296                 case IPPROTO_HOPOPTS:
297                         advance = hbhopt_print(ndo, cp);
298                         if (advance < 0)
299                                 return;
300                         nh = *cp;
301                         break;
302                 case IPPROTO_DSTOPTS:
303                         advance = dstopt_print(ndo, cp);
304                         if (advance < 0)
305                                 return;
306                         nh = *cp;
307                         break;
308                 case IPPROTO_FRAGMENT:
309                         advance = frag6_print(ndo, cp, (const u_char *)ip6);
310                         if (advance < 0 || ndo->ndo_snapend <= cp + advance)
311                                 return;
312                         nh = *cp;
313                         fragmented = 1;
314                         break;
315
316                 case IPPROTO_MOBILITY_OLD:
317                 case IPPROTO_MOBILITY:
318                         /*
319                          * XXX - we don't use "advance"; RFC 3775 says that
320                          * the next header field in a mobility header
321                          * should be IPPROTO_NONE, but speaks of
322                          * the possiblity of a future extension in
323                          * which payload can be piggybacked atop a
324                          * mobility header.
325                          */
326                         advance = mobility_print(ndo, cp, (const u_char *)ip6);
327                         if (advance < 0)
328                                 return;
329                         nh = *cp;
330                         return;
331                 case IPPROTO_ROUTING:
332                         ND_TCHECK(*cp);
333                         advance = rt6_print(ndo, cp, (const u_char *)ip6);
334                         if (advance < 0)
335                                 return;
336                         nh = *cp;
337                         break;
338                 case IPPROTO_SCTP:
339                         sctp_print(ndo, cp, (const u_char *)ip6, len);
340                         return;
341                 case IPPROTO_DCCP:
342                         dccp_print(ndo, cp, (const u_char *)ip6, len);
343                         return;
344                 case IPPROTO_TCP:
345                         tcp_print(ndo, cp, len, (const u_char *)ip6, fragmented);
346                         return;
347                 case IPPROTO_UDP:
348                         udp_print(ndo, cp, len, (const u_char *)ip6, fragmented);
349                         return;
350                 case IPPROTO_ICMPV6:
351                         icmp6_print(ndo, cp, len, (const u_char *)ip6, fragmented);
352                         return;
353                 case IPPROTO_AH:
354                         advance = ah_print(ndo, cp);
355                         if (advance < 0)
356                                 return;
357                         nh = *cp;
358                         break;
359                 case IPPROTO_ESP:
360                     {
361                         int enh, padlen;
362                         advance = esp_print(ndo, cp, len, (const u_char *)ip6, &enh, &padlen);
363                         if (advance < 0)
364                                 return;
365                         nh = enh & 0xff;
366                         len -= padlen;
367                         break;
368                     }
369                 case IPPROTO_IPCOMP:
370                     {
371                         ipcomp_print(ndo, cp);
372                         /*
373                          * Either this has decompressed the payload and
374                          * printed it, in which case there's nothing more
375                          * to do, or it hasn't, in which case there's
376                          * nothing more to do.
377                          */
378                         advance = -1;
379                         break;
380                     }
381
382                 case IPPROTO_PIM:
383                         pim_print(ndo, cp, len, (const u_char *)ip6);
384                         return;
385
386                 case IPPROTO_OSPF:
387                         ospf6_print(ndo, cp, len);
388                         return;
389
390                 case IPPROTO_IPV6:
391                         ip6_print(ndo, cp, len);
392                         return;
393
394                 case IPPROTO_IPV4:
395                         ip_print(ndo, cp, len);
396                         return;
397
398                 case IPPROTO_PGM:
399                         pgm_print(ndo, cp, len, (const u_char *)ip6);
400                         return;
401
402                 case IPPROTO_GRE:
403                         gre_print(ndo, cp, len);
404                         return;
405
406                 case IPPROTO_RSVP:
407                         rsvp_print(ndo, cp, len);
408                         return;
409
410                 case IPPROTO_NONE:
411                         ND_PRINT((ndo, "no next header"));
412                         return;
413
414                 default:
415                         ND_PRINT((ndo, "ip-proto-%d %d", nh, len));
416                         return;
417                 }
418         }
419
420         return;
421 trunc:
422         ND_PRINT((ndo, "[|ip6]"));
423 }