• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
ip6_finddst(netdissect_options * ndo,struct in6_addr * dst,const struct ip6_hdr * ip6)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
nextproto6_cksum(netdissect_options * ndo,const struct ip6_hdr * ip6,const uint8_t * data,u_int len,u_int covlen,u_int next_proto)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
ip6_print(netdissect_options * ndo,const u_char * bp,u_int length)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 }
413