Patch from Bill Fumerola to quiet some EGCS complaints, at least on
[metze/wireshark/wip.git] / packet-ipv6.c
1 /* packet-ipv6.c
2  * Routines for IPv6 packet disassembly 
3  *
4  * $Id: packet-ipv6.c,v 1.12 1999/08/03 03:48:04 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
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.
15  * 
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.
20  * 
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.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #ifdef HAVE_SYS_SOCKET_h
35 #include <sys/socket.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41
42 #include <string.h>
43 #include <stdio.h>
44 #include <glib.h>
45 #include "packet.h"
46 #include "packet-ip.h"
47 #include "packet-ipv6.h"
48 #include "etypes.h"
49 #include "resolv.h"
50
51 static int proto_ipv6 = -1;
52
53 #ifndef offsetof
54 #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
55 #endif
56
57 static const char *
58 inet_ntop6(const u_char *src, char *dst, size_t size);
59
60 static const char *
61 inet_ntop4(const u_char *src, char *dst, size_t size);
62
63 static int
64 dissect_routing6(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
65     return 0;
66 }
67
68 static int
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");
72     }
73     return 0;
74 }
75
76 static int
77 dissect_hopopts(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
78     return 0;
79 }
80
81 static int
82 dissect_dstopts(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
83     struct ip6_dest dstopt;
84     int len;
85     proto_tree *dstopt_tree;
86         proto_item *ti;
87
88     memcpy(&dstopt, (void *) &pd[offset], sizeof(dstopt)); 
89     len = (dstopt.ip6d_len + 1) << 3;
90
91     if (tree) {
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);
96
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);
100   
101         /* decode... */
102     }
103
104     return len;
105 }
106
107
108 void
109 dissect_ipv6(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
110   proto_tree *ipv6_tree;
111   proto_item *ti;
112   guint8 nxt;
113   int advance;
114
115   struct ip6_hdr ipv6;
116
117   memcpy(&ipv6, (void *) &pd[offset], sizeof(ipv6)); 
118
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));
129
130   if (tree) {
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);
134
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);
139
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));
144
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)));
151
152     proto_tree_add_text(ipv6_tree,
153                 offset + offsetof(struct ip6_hdr, ip6_plen), 2,
154                 "Payload Length: %d", ntohs(ipv6.ip6_plen));
155
156     proto_tree_add_text(ipv6_tree,
157                 offset + offsetof(struct ip6_hdr, ip6_nxt), 1,
158                 "Next Header: %d", ipv6.ip6_nxt);
159
160     proto_tree_add_text(ipv6_tree,
161                 offset + offsetof(struct ip6_hdr, ip6_hlim), 1,
162                 "Hop limit: %d", ipv6.ip6_hlim);
163
164     proto_tree_add_text(ipv6_tree,
165                 offset + offsetof(struct ip6_hdr, ip6_src), 16,
166 #ifdef INET6
167                 "Source address: %s (%s)",
168                 get_hostname6(&ipv6.ip6_src),
169 #else
170                 "Source address: %s",
171 #endif
172                 ip6_to_str(&ipv6.ip6_src));
173
174         proto_tree_add_text(ipv6_tree,
175                 offset + offsetof(struct ip6_hdr, ip6_dst), 16,
176 #ifdef INET6
177                 "Destination address: %s (%s)",
178                 get_hostname6(&ipv6.ip6_dst),
179 #else
180                 "Destination address: %s",
181 #endif
182                 ip6_to_str(&ipv6.ip6_dst));
183   }
184
185   /* start of the new header (could be a extension header) */
186   offset += 40;
187   nxt = ipv6.ip6_nxt;
188
189 again:
190     switch (nxt) {
191     case IP_PROTO_HOPOPTS:
192         dissect_hopopts(pd, offset, fd, tree);
193 #if 0
194         goto again;
195 #else
196         break;
197 #endif
198     case IP_PROTO_IPIP:
199         dissect_ip(pd, offset, fd, tree);
200         break;
201     case IP_PROTO_ROUTING:
202         dissect_routing6(pd, offset, fd, tree);
203 #if 0
204         goto again;
205 #else
206         break;
207 #endif
208     case IP_PROTO_FRAGMENT:
209         dissect_frag6(pd, offset, fd, tree);
210 #if 0
211         goto again;
212 #else
213         break;
214 #endif
215     case IP_PROTO_ICMPV6:
216         dissect_icmpv6(pd, offset, fd, tree);
217         break;
218     case IP_PROTO_NONE:
219         if (check_col(fd, COL_INFO)) {
220             col_add_fstr(fd, COL_INFO, "IPv6 no next header");
221         }
222         break;
223     case IP_PROTO_AH:
224         advance = dissect_ah(pd, offset, fd, tree);
225         nxt = pd[offset];
226         offset += advance;
227         goto again;
228     case IP_PROTO_ESP:
229         dissect_esp(pd, offset, fd, tree);
230         break;
231     case IP_PROTO_DSTOPTS:
232         advance = dissect_dstopts(pd, offset, fd, tree);
233         nxt = pd[offset];
234         offset += advance;
235         goto again;
236     case IP_PROTO_TCP:
237         dissect_tcp(pd, offset, fd, tree);
238         break;
239     case IP_PROTO_UDP:
240         dissect_udp(pd, offset, fd, tree);
241         break;
242     default:
243         if (check_col(fd, COL_INFO)) {
244             col_add_fstr(fd, COL_INFO, "Unknown IPv6 protocol (0x%02x)",
245                 ipv6.ip6_nxt);
246         }
247         dissect_data(pd, offset, fd, tree);
248     }
249 }
250
251 gchar *
252 ip6_to_str(struct e_in6_addr *ad) {
253   static gchar buf[4 * 8 + 8];
254
255   inet_ntop6((u_char*)ad, (gchar*)buf, sizeof(buf));
256   return buf;
257 }
258
259 #ifndef NS_IN6ADDRSZ
260 #define NS_IN6ADDRSZ    16
261 #endif
262
263 #ifndef NS_INT16SZ
264 #define NS_INT16SZ      (sizeof(guint16))
265 #endif
266
267 #define SPRINTF(x) ((size_t)sprintf x)
268
269 /*
270  * Copyright (c) 1996-1999 by Internet Software Consortium.
271  *
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.
275  *
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
283  * SOFTWARE.
284  */
285
286 /* const char *
287  * inet_ntop4(src, dst, size)
288  *      format an IPv4 address
289  * return:
290  *      `dst' (as a const)
291  * notes:
292  *      (1) uses no statics
293  *      (2) takes a u_char* not an in_addr as input
294  * author:
295  *      Paul Vixie, 1996.
296  */
297 static const char *
298 inet_ntop4(src, dst, size)
299         const u_char *src;
300         char *dst;
301         size_t size;
302 {
303         static const char fmt[] = "%u.%u.%u.%u";
304         char tmp[sizeof "255.255.255.255"];
305
306         if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) {
307                 return (NULL);
308         }
309         strcpy(dst, tmp);
310         return (dst);
311 }
312
313 /* const char *
314  * inet_ntop6(src, dst, size)
315  *      convert IPv6 binary address into presentation (printable) format
316  * author:
317  *      Paul Vixie, 1996.
318  */
319 static const char *
320 inet_ntop6(src, dst, size)
321         const u_char *src;
322         char *dst;
323         size_t size;
324 {
325         /*
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.
331          */
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];
335         int i;
336
337         /*
338          * Preprocess:
339          *      Copy the input (bytewise) array into a wordwise array.
340          *      Find the longest run of 0x00's in src[] for :: shorthanding.
341          */
342         memset(words, '\0', sizeof words);
343         for (i = 0; i < NS_IN6ADDRSZ; i++)
344                 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
345         best.base = -1;
346         cur.base = -1;
347         for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
348                 if (words[i] == 0) {
349                         if (cur.base == -1)
350                                 cur.base = i, cur.len = 1;
351                         else
352                                 cur.len++;
353                 } else {
354                         if (cur.base != -1) {
355                                 if (best.base == -1 || cur.len > best.len)
356                                         best = cur;
357                                 cur.base = -1;
358                         }
359                 }
360         }
361         if (cur.base != -1) {
362                 if (best.base == -1 || cur.len > best.len)
363                         best = cur;
364         }
365         if (best.base != -1 && best.len < 2)
366                 best.base = -1;
367
368         /*
369          * Format the result.
370          */
371         tp = tmp;
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)) {
376                         if (i == best.base)
377                                 *tp++ = ':';
378                         continue;
379                 }
380                 /* Are we following an initial run of 0x00s or any real hex? */
381                 if (i != 0)
382                         *tp++ = ':';
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)))
387                                 return (NULL);
388                         tp += strlen(tp);
389                         break;
390                 }
391                 tp += SPRINTF((tp, "%x", words[i]));
392         }
393         /* Was it a trailing run of 0x00's? */
394         if (best.base != -1 && (best.base + best.len) == 
395             (NS_IN6ADDRSZ / NS_INT16SZ))
396                 *tp++ = ':';
397         *tp++ = '\0';
398
399         /*
400          * Check for overflow, copy, and we're done.
401          */
402         if ((size_t)(tp - tmp) > size) {
403                 return (NULL);
404         }
405         strcpy(dst, tmp);
406         return (dst);
407 }
408
409 void
410 proto_register_ipv6(void)
411 {
412 /*        static hf_register_info hf[] = {
413                 { &variable,
414                 { "Name",           "ipv6.abbreviation", TYPE, VALS_POINTER }},
415         };*/
416
417         proto_ipv6 = proto_register_protocol("Internet Protocol Version 6", "ipv6");
418  /*       proto_register_field_array(proto_ipv6, hf, array_length(hf));*/
419 }