print-ip6opts.c revision 98524
1/*
2 * Copyright (C) 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#ifndef lint
35static const char rcsid[] =
36     "@(#) $Header: /tcpdump/master/tcpdump/print-ip6opts.c,v 1.9 2001/05/09 02:47:26 itojun Exp $";
37#endif
38
39#ifdef INET6
40#include <sys/param.h>
41#include <sys/time.h>
42#include <sys/types.h>
43#include <sys/socket.h>
44
45#include <netinet/in.h>
46#include <stdio.h>
47
48#include "ip6.h"
49
50#include "interface.h"
51#include "addrtoname.h"
52
53/* items outside of rfc2292bis */
54#ifndef IP6OPT_MINLEN
55#define IP6OPT_MINLEN	2
56#endif
57#ifndef IP6OPT_RTALERT_LEN
58#define IP6OPT_RTALERT_LEN	4
59#endif
60#ifndef IP6OPT_JUMBO_LEN
61#define IP6OPT_JUMBO_LEN	6
62#endif
63#define IP6OPT_HOMEADDR_MINLEN 18
64#define IP6OPT_BU_MINLEN       10
65#define IP6OPT_BA_MINLEN       13
66#define IP6OPT_BR_MINLEN        2
67#define IP6SOPT_ALTCOA        0x4
68#define IP6SOPT_ALTCOA_MINLEN  18
69#define IP6SOPT_UI            0x2
70#define IP6SOPT_UI_MINLEN       4
71
72static void ip6_sopt_print(const u_char *, int);
73
74static void
75ip6_sopt_print(const u_char *bp, int len)
76{
77    int i;
78    int optlen;
79
80    for (i = 0; i < len; i += optlen) {
81	if (bp[i] == IP6OPT_PAD1)
82	    optlen = 1;
83	else {
84	    if (i + 1 < len)
85		optlen = bp[i + 1] + 2;
86	    else
87		goto trunc;
88	}
89	if (i + optlen > len)
90	    goto trunc;
91
92	switch (bp[i]) {
93	case IP6OPT_PAD1:
94            printf(", pad1");
95	    break;
96	case IP6OPT_PADN:
97	    if (len - i < IP6OPT_MINLEN) {
98		printf(", padn: trunc");
99		goto trunc;
100	    }
101            printf(", padn");
102	    break;
103        case IP6SOPT_ALTCOA:
104             if (len - i < IP6SOPT_ALTCOA_MINLEN) {
105		printf(", altcoa: trunc");
106		goto trunc;
107	    }
108            printf(", alt-CoA: %s", ip6addr_string(&bp[i+2]));
109	    break;
110        case IP6SOPT_UI:
111             if (len - i < IP6SOPT_UI_MINLEN) {
112		printf(", ui: trunc");
113		goto trunc;
114	    }
115            printf("(ui: 0x%04x) ", ntohs(*(u_int16_t *)&bp[i + 2]));
116	    break;
117	default:
118	    if (len - i < IP6OPT_MINLEN) {
119		printf(", sopt_type %d: trunc)", bp[i]);
120		goto trunc;
121	    }
122	    printf(", sopt_type 0x%02x: len=%d", bp[i], bp[i + 1]);
123	    break;
124	}
125    }
126    return;
127
128trunc:
129    printf("[trunc] ");
130}
131
132void
133ip6_opt_print(const u_char *bp, int len)
134{
135    int i;
136    int optlen;
137
138    for (i = 0; i < len; i += optlen) {
139	if (bp[i] == IP6OPT_PAD1)
140	    optlen = 1;
141	else {
142	    if (i + 1 < len)
143		optlen = bp[i + 1] + 2;
144	    else
145		goto trunc;
146	}
147	if (i + optlen > len)
148	    goto trunc;
149
150	switch (bp[i]) {
151	case IP6OPT_PAD1:
152            printf("(pad1)");
153	    break;
154	case IP6OPT_PADN:
155	    if (len - i < IP6OPT_MINLEN) {
156		printf("(padn: trunc)");
157		goto trunc;
158	    }
159            printf("(padn)");
160	    break;
161	case IP6OPT_ROUTER_ALERT:
162	    if (len - i < IP6OPT_RTALERT_LEN) {
163		printf("(rtalert: trunc)");
164		goto trunc;
165	    }
166	    if (bp[i + 1] != IP6OPT_RTALERT_LEN - 2) {
167		printf("(rtalert: invalid len %d)", bp[i + 1]);
168		goto trunc;
169	    }
170	    printf("(rtalert: 0x%04x) ", ntohs(*(u_int16_t *)&bp[i + 2]));
171	    break;
172	case IP6OPT_JUMBO:
173	    if (len - i < IP6OPT_JUMBO_LEN) {
174		printf("(jumbo: trunc)");
175		goto trunc;
176	    }
177	    if (bp[i + 1] != IP6OPT_JUMBO_LEN - 2) {
178		printf("(jumbo: invalid len %d)", bp[i + 1]);
179		goto trunc;
180	    }
181	    printf("(jumbo: %u) ", (u_int32_t)ntohl(*(u_int32_t *)&bp[i + 2]));
182	    break;
183        case IP6OPT_HOME_ADDRESS:
184	    if (len - i < IP6OPT_HOMEADDR_MINLEN) {
185		printf("(homeaddr: trunc)");
186		goto trunc;
187	    }
188	    if (bp[i + 1] < IP6OPT_HOMEADDR_MINLEN - 2) {
189		printf("(homeaddr: invalid len %d)", bp[i + 1]);
190		goto trunc;
191	    }
192	    printf("(homeaddr: %s", ip6addr_string(&bp[i + 2]));
193            if (bp[i + 1] > IP6OPT_HOMEADDR_MINLEN - 2) {
194		ip6_sopt_print(&bp[i + IP6OPT_HOMEADDR_MINLEN],
195		    (optlen - IP6OPT_HOMEADDR_MINLEN));
196	    }
197            printf(")");
198	    break;
199        case IP6OPT_BINDING_UPDATE:
200	    if (len - i < IP6OPT_BU_MINLEN) {
201		printf("(bu: trunc)");
202		goto trunc;
203	    }
204	    if (bp[i + 1] < IP6OPT_BU_MINLEN - 2) {
205		printf("(bu: invalid len %d)", bp[i + 1]);
206		goto trunc;
207	    }
208	    printf("(bu: ");
209	    if (bp[i + 2] & 0x80)
210		    printf("A");
211	    if (bp[i + 2] & 0x40)
212		    printf("H");
213	    if (bp[i + 2] & 0x20)
214		    printf("R");
215	    if (bp[i + 2] & 0x10)
216		    printf("D");
217	    if (bp[i + 2] & 0x0f)
218		    printf("res");
219	    printf(", prefixlen: %u", bp[i + 3]);
220	    printf(", sequence: %u",
221		(u_int16_t)ntohs(*(u_int16_t *)&bp[i + 4]));
222	    printf(", lifetime: %u",
223		(u_int32_t)ntohs(*(u_int32_t *)&bp[i + 8]));
224
225	    if (bp[i + 1] > IP6OPT_BU_MINLEN - 2) {
226		ip6_sopt_print(&bp[i + IP6OPT_BU_MINLEN],
227		    (optlen - IP6OPT_BU_MINLEN));
228	    }
229	    printf(")");
230	    break;
231	case IP6OPT_BINDING_ACK:
232	    if (len - i < IP6OPT_BA_MINLEN) {
233		printf("(ba: trunc)");
234		goto trunc;
235	    }
236	    if (bp[i + 1] < IP6OPT_BA_MINLEN - 2) {
237		printf("(ba: invalid len %d)", bp[i + 1]);
238		goto trunc;
239	    }
240	    printf("(ba: ");
241	    printf("status: %u", bp[i + 2]);
242	    printf(", sequence: %u",
243		(u_int16_t)ntohs(*(u_int16_t *)&bp[i + 3]));
244	    printf(", lifetime: %u",
245		(u_int32_t)ntohs(*(u_int32_t *)&bp[i + 7]));
246	    printf(", refresh: %u",
247		(u_int32_t)ntohs(*(u_int32_t *)&bp[i + 11]));
248
249	    if (bp[i + 1] > IP6OPT_BA_MINLEN - 2) {
250		ip6_sopt_print(&bp[i + IP6OPT_BA_MINLEN],
251		    (optlen - IP6OPT_BA_MINLEN));
252	    }
253            printf(")");
254	    break;
255        case IP6OPT_BINDING_REQ:
256	    if (len - i < IP6OPT_BR_MINLEN) {
257		printf("(br: trunc)");
258		goto trunc;
259	    }
260            printf("(br");
261            if (bp[i + 1] > IP6OPT_BR_MINLEN - 2) {
262		ip6_sopt_print(&bp[i + IP6OPT_BR_MINLEN],
263		    (optlen - IP6OPT_BR_MINLEN));
264	    }
265            printf(")");
266	    break;
267	default:
268	    if (len - i < IP6OPT_MINLEN) {
269		printf("(type %d: trunc)", bp[i]);
270		goto trunc;
271	    }
272	    printf("(opt_type 0x%02x: len=%d) ", bp[i], bp[i + 1]);
273	    break;
274	}
275    }
276
277#if 0
278end:
279#endif
280    return;
281
282trunc:
283    printf("[trunc] ");
284}
285
286int
287hbhopt_print(register const u_char *bp)
288{
289    const struct ip6_hbh *dp = (struct ip6_hbh *)bp;
290    register const u_char *ep;
291    int hbhlen = 0;
292
293    /* 'ep' points to the end of available data. */
294    ep = snapend;
295    TCHECK(dp->ip6h_len);
296    hbhlen = (int)((dp->ip6h_len + 1) << 3);
297    TCHECK2(*dp, hbhlen);
298    printf("HBH ");
299    if (vflag)
300	ip6_opt_print((const u_char *)dp + sizeof(*dp), hbhlen - sizeof(*dp));
301
302    return(hbhlen);
303
304  trunc:
305    fputs("[|HBH]", stdout);
306    return(hbhlen);
307}
308
309int
310dstopt_print(register const u_char *bp)
311{
312    const struct ip6_dest *dp = (struct ip6_dest *)bp;
313    register const u_char *ep;
314    int dstoptlen = 0;
315
316    /* 'ep' points to the end of available data. */
317    ep = snapend;
318    TCHECK(dp->ip6d_len);
319    dstoptlen = (int)((dp->ip6d_len + 1) << 3);
320    TCHECK2(*dp, dstoptlen);
321    printf("DSTOPT ");
322    if (vflag) {
323	ip6_opt_print((const u_char *)dp + sizeof(*dp),
324	    dstoptlen - sizeof(*dp));
325    }
326
327    return(dstoptlen);
328
329  trunc:
330    fputs("[|DSTOPT]", stdout);
331    return(dstoptlen);
332}
333#endif /* INET6 */
334