2 * Routines for IPv6 packet disassembly
4 * $Id: packet-ipv6.c,v 1.12 1999/08/03 03:48:04 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
34 #ifdef HAVE_SYS_SOCKET_h
35 #include <sys/socket.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
46 #include "packet-ip.h"
47 #include "packet-ipv6.h"
51 static int proto_ipv6 = -1;
54 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
58 inet_ntop6(const u_char *src, char *dst, size_t size);
61 inet_ntop4(const u_char *src, char *dst, size_t size);
64 dissect_routing6(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
69 dissect_frag6(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
70 if (check_col(fd, COL_INFO)) {
71 col_add_fstr(fd, COL_INFO, "IPv6 fragment");
77 dissect_hopopts(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
82 dissect_dstopts(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
83 struct ip6_dest dstopt;
85 proto_tree *dstopt_tree;
88 memcpy(&dstopt, (void *) &pd[offset], sizeof(dstopt));
89 len = (dstopt.ip6d_len + 1) << 3;
92 /* !!! specify length */
93 ti = proto_tree_add_text(tree, offset, len,
94 "Destination Option Header");
95 dstopt_tree = proto_item_add_subtree(ti, ETT_IPv6);
97 proto_tree_add_text(dstopt_tree,
98 offset + offsetof(struct ip6_dest, ip6d_len), 1,
99 "Length: %d (%d bytes)", dstopt.ip6d_len, len);
109 dissect_ipv6(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
110 proto_tree *ipv6_tree;
117 memcpy(&ipv6, (void *) &pd[offset], sizeof(ipv6));
119 if (check_col(fd, COL_PROTOCOL))
120 col_add_str(fd, COL_PROTOCOL, "IPv6");
121 if (check_col(fd, COL_RES_NET_SRC))
122 col_add_str(fd, COL_RES_NET_SRC, get_hostname6(&ipv6.ip6_src));
123 if (check_col(fd, COL_UNRES_NET_SRC))
124 col_add_str(fd, COL_UNRES_NET_SRC, ip6_to_str(&ipv6.ip6_src));
125 if (check_col(fd, COL_RES_NET_DST))
126 col_add_str(fd, COL_RES_NET_DST, get_hostname6(&ipv6.ip6_dst));
127 if (check_col(fd, COL_UNRES_NET_DST))
128 col_add_str(fd, COL_UNRES_NET_DST, ip6_to_str(&ipv6.ip6_dst));
131 /* !!! specify length */
132 ti = proto_tree_add_item(tree, proto_ipv6, offset, 40, NULL);
133 ipv6_tree = proto_item_add_subtree(ti, ETT_IPv6);
135 /* !!! warning: version also contains 4 Bit priority */
136 proto_tree_add_text(ipv6_tree,
137 offset + offsetof(struct ip6_hdr, ip6_vfc), 1,
138 "Version: %d", ipv6.ip6_vfc >> 4);
140 proto_tree_add_text(ipv6_tree,
141 offset + offsetof(struct ip6_hdr, ip6_flow), 4,
142 "Traffic class: 0x%02lx",
143 (unsigned long)((ntohl(ipv6.ip6_flow) >> 20) & 0xff));
145 /* there should be no alignment problems for ip6_flow, since it's the first
146 guint32 in the ipv6 struct */
147 proto_tree_add_text(ipv6_tree,
148 offset + offsetof(struct ip6_hdr, ip6_flow), 4,
149 "Flowlabel: 0x%05lx",
150 (unsigned long)(ntohl(ipv6.ip6_flow & IPV6_FLOWLABEL_MASK)));
152 proto_tree_add_text(ipv6_tree,
153 offset + offsetof(struct ip6_hdr, ip6_plen), 2,
154 "Payload Length: %d", ntohs(ipv6.ip6_plen));
156 proto_tree_add_text(ipv6_tree,
157 offset + offsetof(struct ip6_hdr, ip6_nxt), 1,
158 "Next Header: %d", ipv6.ip6_nxt);
160 proto_tree_add_text(ipv6_tree,
161 offset + offsetof(struct ip6_hdr, ip6_hlim), 1,
162 "Hop limit: %d", ipv6.ip6_hlim);
164 proto_tree_add_text(ipv6_tree,
165 offset + offsetof(struct ip6_hdr, ip6_src), 16,
167 "Source address: %s (%s)",
168 get_hostname6(&ipv6.ip6_src),
170 "Source address: %s",
172 ip6_to_str(&ipv6.ip6_src));
174 proto_tree_add_text(ipv6_tree,
175 offset + offsetof(struct ip6_hdr, ip6_dst), 16,
177 "Destination address: %s (%s)",
178 get_hostname6(&ipv6.ip6_dst),
180 "Destination address: %s",
182 ip6_to_str(&ipv6.ip6_dst));
185 /* start of the new header (could be a extension header) */
191 case IP_PROTO_HOPOPTS:
192 dissect_hopopts(pd, offset, fd, tree);
199 dissect_ip(pd, offset, fd, tree);
201 case IP_PROTO_ROUTING:
202 dissect_routing6(pd, offset, fd, tree);
208 case IP_PROTO_FRAGMENT:
209 dissect_frag6(pd, offset, fd, tree);
215 case IP_PROTO_ICMPV6:
216 dissect_icmpv6(pd, offset, fd, tree);
219 if (check_col(fd, COL_INFO)) {
220 col_add_fstr(fd, COL_INFO, "IPv6 no next header");
224 advance = dissect_ah(pd, offset, fd, tree);
229 dissect_esp(pd, offset, fd, tree);
231 case IP_PROTO_DSTOPTS:
232 advance = dissect_dstopts(pd, offset, fd, tree);
237 dissect_tcp(pd, offset, fd, tree);
240 dissect_udp(pd, offset, fd, tree);
243 if (check_col(fd, COL_INFO)) {
244 col_add_fstr(fd, COL_INFO, "Unknown IPv6 protocol (0x%02x)",
247 dissect_data(pd, offset, fd, tree);
252 ip6_to_str(struct e_in6_addr *ad) {
253 static gchar buf[4 * 8 + 8];
255 inet_ntop6((u_char*)ad, (gchar*)buf, sizeof(buf));
260 #define NS_IN6ADDRSZ 16
264 #define NS_INT16SZ (sizeof(guint16))
267 #define SPRINTF(x) ((size_t)sprintf x)
270 * Copyright (c) 1996-1999 by Internet Software Consortium.
272 * Permission to use, copy, modify, and distribute this software for any
273 * purpose with or without fee is hereby granted, provided that the above
274 * copyright notice and this permission notice appear in all copies.
276 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
277 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
278 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
279 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
280 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
281 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
282 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
287 * inet_ntop4(src, dst, size)
288 * format an IPv4 address
292 * (1) uses no statics
293 * (2) takes a u_char* not an in_addr as input
298 inet_ntop4(src, dst, size)
303 static const char fmt[] = "%u.%u.%u.%u";
304 char tmp[sizeof "255.255.255.255"];
306 if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) {
314 * inet_ntop6(src, dst, size)
315 * convert IPv6 binary address into presentation (printable) format
320 inet_ntop6(src, dst, size)
326 * Note that int32_t and int16_t need only be "at least" large enough
327 * to contain a value of the specified size. On some systems, like
328 * Crays, there is no such thing as an integer variable with 16 bits.
329 * Keep this in mind if you think this function should have been coded
330 * to use pointer overlays. All the world's not a VAX.
332 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
333 struct { int base, len; } best, cur;
334 u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
339 * Copy the input (bytewise) array into a wordwise array.
340 * Find the longest run of 0x00's in src[] for :: shorthanding.
342 memset(words, '\0', sizeof words);
343 for (i = 0; i < NS_IN6ADDRSZ; i++)
344 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
347 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
350 cur.base = i, cur.len = 1;
354 if (cur.base != -1) {
355 if (best.base == -1 || cur.len > best.len)
361 if (cur.base != -1) {
362 if (best.base == -1 || cur.len > best.len)
365 if (best.base != -1 && best.len < 2)
372 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
373 /* Are we inside the best run of 0x00's? */
374 if (best.base != -1 && i >= best.base &&
375 i < (best.base + best.len)) {
380 /* Are we following an initial run of 0x00s or any real hex? */
383 /* Is this address an encapsulated IPv4? */
384 if (i == 6 && best.base == 0 &&
385 (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
386 if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
391 tp += SPRINTF((tp, "%x", words[i]));
393 /* Was it a trailing run of 0x00's? */
394 if (best.base != -1 && (best.base + best.len) ==
395 (NS_IN6ADDRSZ / NS_INT16SZ))
400 * Check for overflow, copy, and we're done.
402 if ((size_t)(tp - tmp) > size) {
410 proto_register_ipv6(void)
412 /* static hf_register_info hf[] = {
414 { "Name", "ipv6.abbreviation", TYPE, VALS_POINTER }},
417 proto_ipv6 = proto_register_protocol("Internet Protocol Version 6", "ipv6");
418 /* proto_register_field_array(proto_ipv6, hf, array_length(hf));*/