• 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 #define NETDISSECT_REWORKED
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <tcpdump-stdinc.h>
28 
29 #include <string.h>
30 
31 #include "interface.h"
32 #include "addrtoname.h"
33 #include "extract.h"
34 
35 #ifdef INET6
36 
37 #include "ip6.h"
38 #include "ipproto.h"
39 
40 /*
41  * Compute a V6-style checksum by building a pseudoheader.
42  */
43 int
nextproto6_cksum(const struct ip6_hdr * ip6,const uint8_t * data,u_int len,u_int covlen,u_int next_proto)44 nextproto6_cksum(const struct ip6_hdr *ip6, const uint8_t *data,
45 		 u_int len, u_int covlen, u_int next_proto)
46 {
47         struct {
48                 struct in6_addr ph_src;
49                 struct in6_addr ph_dst;
50                 uint32_t       ph_len;
51                 uint8_t        ph_zero[3];
52                 uint8_t        ph_nxt;
53         } ph;
54         struct cksum_vec vec[2];
55 
56         /* pseudo-header */
57         memset(&ph, 0, sizeof(ph));
58         UNALIGNED_MEMCPY(&ph.ph_src, &ip6->ip6_src, sizeof (struct in6_addr));
59         UNALIGNED_MEMCPY(&ph.ph_dst, &ip6->ip6_dst, sizeof (struct in6_addr));
60         ph.ph_len = htonl(len);
61         ph.ph_nxt = next_proto;
62 
63         vec[0].ptr = (const uint8_t *)(void *)&ph;
64         vec[0].len = sizeof(ph);
65         vec[1].ptr = data;
66         vec[1].len = covlen;
67 
68         return in_cksum(vec, 2);
69 }
70 
71 /*
72  * print an IP6 datagram.
73  */
74 void
ip6_print(netdissect_options * ndo,const u_char * bp,u_int length)75 ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
76 {
77 	register const struct ip6_hdr *ip6;
78 	register int advance;
79 	u_int len;
80 	const u_char *ipend;
81 	register const u_char *cp;
82 	register u_int payload_len;
83 	int nh;
84 	int fragmented = 0;
85 	u_int flow;
86 
87 	ip6 = (const struct ip6_hdr *)bp;
88 
89 	ND_TCHECK(*ip6);
90 	if (length < sizeof (struct ip6_hdr)) {
91 		ND_PRINT((ndo, "truncated-ip6 %u", length));
92 		return;
93 	}
94 
95         if (!ndo->ndo_eflag)
96             ND_PRINT((ndo, "IP6 "));
97 
98 	if (IP6_VERSION(ip6) != 6) {
99           ND_PRINT((ndo,"version error: %u != 6", IP6_VERSION(ip6)));
100           return;
101 	}
102 
103 	payload_len = EXTRACT_16BITS(&ip6->ip6_plen);
104 	len = payload_len + sizeof(struct ip6_hdr);
105 	if (length < len)
106 		ND_PRINT((ndo, "truncated-ip6 - %u bytes missing!",
107 			len - length));
108 
109         if (ndo->ndo_vflag) {
110             flow = EXTRACT_32BITS(&ip6->ip6_flow);
111             ND_PRINT((ndo, "("));
112 #if 0
113             /* rfc1883 */
114             if (flow & 0x0f000000)
115 		ND_PRINT((ndo, "pri 0x%02x, ", (flow & 0x0f000000) >> 24));
116             if (flow & 0x00ffffff)
117 		ND_PRINT((ndo, "flowlabel 0x%06x, ", flow & 0x00ffffff));
118 #else
119             /* RFC 2460 */
120             if (flow & 0x0ff00000)
121 		ND_PRINT((ndo, "class 0x%02x, ", (flow & 0x0ff00000) >> 20));
122             if (flow & 0x000fffff)
123 		ND_PRINT((ndo, "flowlabel 0x%05x, ", flow & 0x000fffff));
124 #endif
125 
126             ND_PRINT((ndo, "hlim %u, next-header %s (%u) payload length: %u) ",
127                          ip6->ip6_hlim,
128                          tok2str(ipproto_values,"unknown",ip6->ip6_nxt),
129                          ip6->ip6_nxt,
130                          payload_len));
131         }
132 
133 	/*
134 	 * Cut off the snapshot length to the end of the IP payload.
135 	 */
136 	ipend = bp + len;
137 	if (ipend < ndo->ndo_snapend)
138 		ndo->ndo_snapend = ipend;
139 
140 	cp = (const u_char *)ip6;
141 	advance = sizeof(struct ip6_hdr);
142 	nh = ip6->ip6_nxt;
143 	while (cp < ndo->ndo_snapend && advance > 0) {
144 		cp += advance;
145 		len -= advance;
146 
147 		if (cp == (const u_char *)(ip6 + 1) &&
148 		    nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
149 		    nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
150 			ND_PRINT((ndo, "%s > %s: ", ip6addr_string(ndo, &ip6->ip6_src),
151 				     ip6addr_string(ndo, &ip6->ip6_dst)));
152 		}
153 
154 		switch (nh) {
155 		case IPPROTO_HOPOPTS:
156 			advance = hbhopt_print(ndo, cp);
157 			nh = *cp;
158 			break;
159 		case IPPROTO_DSTOPTS:
160 			advance = dstopt_print(ndo, cp);
161 			nh = *cp;
162 			break;
163 		case IPPROTO_FRAGMENT:
164 			advance = frag6_print(ndo, cp, (const u_char *)ip6);
165 			if (ndo->ndo_snapend <= cp + advance)
166 				return;
167 			nh = *cp;
168 			fragmented = 1;
169 			break;
170 
171 		case IPPROTO_MOBILITY_OLD:
172 		case IPPROTO_MOBILITY:
173 			/*
174 			 * XXX - we don't use "advance"; the current
175 			 * "Mobility Support in IPv6" draft
176 			 * (draft-ietf-mobileip-ipv6-24) says that
177 			 * the next header field in a mobility header
178 			 * should be IPPROTO_NONE, but speaks of
179 			 * the possiblity of a future extension in
180 			 * which payload can be piggybacked atop a
181 			 * mobility header.
182 			 */
183 			advance = mobility_print(ndo, cp, (const u_char *)ip6);
184 			nh = *cp;
185 			return;
186 		case IPPROTO_ROUTING:
187 			advance = rt6_print(ndo, cp, (const u_char *)ip6);
188 			nh = *cp;
189 			break;
190 		case IPPROTO_SCTP:
191 			sctp_print(ndo, cp, (const u_char *)ip6, len);
192 			return;
193 		case IPPROTO_DCCP:
194 			dccp_print(ndo, cp, (const u_char *)ip6, len);
195 			return;
196 		case IPPROTO_TCP:
197 			tcp_print(ndo, cp, len, (const u_char *)ip6, fragmented);
198 			return;
199 		case IPPROTO_UDP:
200 			udp_print(ndo, cp, len, (const u_char *)ip6, fragmented);
201 			return;
202 		case IPPROTO_ICMPV6:
203 			icmp6_print(ndo, cp, len, (const u_char *)ip6, fragmented);
204 			return;
205 		case IPPROTO_AH:
206 			advance = ah_print(ndo, cp);
207 			nh = *cp;
208 			break;
209 		case IPPROTO_ESP:
210 		    {
211 			int enh, padlen;
212 			advance = esp_print(ndo, cp, len, (const u_char *)ip6, &enh, &padlen);
213 			nh = enh & 0xff;
214 			len -= padlen;
215 			break;
216 		    }
217 		case IPPROTO_IPCOMP:
218 		    {
219 			int enh;
220 			advance = ipcomp_print(ndo, cp, &enh);
221 			nh = enh & 0xff;
222 			break;
223 		    }
224 
225 		case IPPROTO_PIM:
226 			pim_print(ndo, cp, len, nextproto6_cksum(ip6, cp, len, len,
227 							    IPPROTO_PIM));
228 			return;
229 
230 		case IPPROTO_OSPF:
231 			ospf6_print(ndo, cp, len);
232 			return;
233 
234 		case IPPROTO_IPV6:
235 			ip6_print(ndo, cp, len);
236 			return;
237 
238 		case IPPROTO_IPV4:
239 		        ip_print(ndo, cp, len);
240 			return;
241 
242                 case IPPROTO_PGM:
243                         pgm_print(ndo, cp, len, (const u_char *)ip6);
244                         return;
245 
246 		case IPPROTO_GRE:
247 			gre_print(ndo, cp, len);
248 			return;
249 
250 		case IPPROTO_RSVP:
251 			rsvp_print(ndo, cp, len);
252 			return;
253 
254 		case IPPROTO_NONE:
255 			ND_PRINT((ndo, "no next header"));
256 			return;
257 
258 		default:
259 			ND_PRINT((ndo, "ip-proto-%d %d", nh, len));
260 			return;
261 		}
262 	}
263 
264 	return;
265 trunc:
266 	ND_PRINT((ndo, "[|ip6]"));
267 }
268 
269 #else /* INET6 */
270 
271 void
ip6_print(netdissect_options * ndo,const u_char * bp _U_,u_int length)272 ip6_print(netdissect_options *ndo, const u_char *bp _U_, u_int length)
273 {
274 	ND_PRINT((ndo, "IP6, length: %u (printing not supported)", length));
275 }
276 
277 #endif /* INET6 */
278