xref: /netbsd-src/external/bsd/tcpdump/dist/print-ip6opts.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
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 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static const char rcsid[] _U_ =
38      "@(#) Header: /tcpdump/master/tcpdump/print-ip6opts.c,v 1.18 2005-04-20 22:18:50 guy Exp";
39 #else
40 __RCSID("$NetBSD: print-ip6opts.c,v 1.2 2010/12/05 05:11:30 christos Exp $");
41 #endif
42 #endif
43 
44 #ifdef INET6
45 #include <tcpdump-stdinc.h>
46 
47 #include <stdio.h>
48 
49 #include "ip6.h"
50 
51 #include "interface.h"
52 #include "addrtoname.h"
53 #include "extract.h"
54 
55 /* items outside of rfc2292bis */
56 #ifndef IP6OPT_MINLEN
57 #define IP6OPT_MINLEN	2
58 #endif
59 #ifndef IP6OPT_RTALERT_LEN
60 #define IP6OPT_RTALERT_LEN	4
61 #endif
62 #ifndef IP6OPT_JUMBO_LEN
63 #define IP6OPT_JUMBO_LEN	6
64 #endif
65 #define IP6OPT_HOMEADDR_MINLEN 18
66 #define IP6OPT_BU_MINLEN       10
67 #define IP6OPT_BA_MINLEN       13
68 #define IP6OPT_BR_MINLEN        2
69 #define IP6SOPT_UI            0x2
70 #define IP6SOPT_UI_MINLEN       4
71 #define IP6SOPT_ALTCOA        0x3
72 #define IP6SOPT_ALTCOA_MINLEN  18
73 #define IP6SOPT_AUTH          0x4
74 #define IP6SOPT_AUTH_MINLEN     6
75 
76 static void ip6_sopt_print(const u_char *, int);
77 
78 static void
79 ip6_sopt_print(const u_char *bp, int len)
80 {
81     int i;
82     int optlen;
83 
84     for (i = 0; i < len; i += optlen) {
85 	if (bp[i] == IP6OPT_PAD1)
86 	    optlen = 1;
87 	else {
88 	    if (i + 1 < len)
89 		optlen = bp[i + 1] + 2;
90 	    else
91 		goto trunc;
92 	}
93 	if (i + optlen > len)
94 	    goto trunc;
95 
96 	switch (bp[i]) {
97 	case IP6OPT_PAD1:
98             printf(", pad1");
99 	    break;
100 	case IP6OPT_PADN:
101 	    if (len - i < IP6OPT_MINLEN) {
102 		printf(", padn: trunc");
103 		goto trunc;
104 	    }
105             printf(", padn");
106 	    break;
107         case IP6SOPT_UI:
108              if (len - i < IP6SOPT_UI_MINLEN) {
109 		printf(", ui: trunc");
110 		goto trunc;
111 	    }
112             printf(", ui: 0x%04x ", EXTRACT_16BITS(&bp[i + 2]));
113 	    break;
114         case IP6SOPT_ALTCOA:
115              if (len - i < IP6SOPT_ALTCOA_MINLEN) {
116 		printf(", altcoa: trunc");
117 		goto trunc;
118 	    }
119             printf(", alt-CoA: %s", ip6addr_string(&bp[i+2]));
120 	    break;
121         case IP6SOPT_AUTH:
122              if (len - i < IP6SOPT_AUTH_MINLEN) {
123 		printf(", auth: trunc");
124 		goto trunc;
125 	    }
126             printf(", auth spi: 0x%08x", EXTRACT_32BITS(&bp[i + 2]));
127 	    break;
128 	default:
129 	    if (len - i < IP6OPT_MINLEN) {
130 		printf(", sopt_type %d: trunc)", bp[i]);
131 		goto trunc;
132 	    }
133 	    printf(", sopt_type 0x%02x: len=%d", bp[i], bp[i + 1]);
134 	    break;
135 	}
136     }
137     return;
138 
139 trunc:
140     printf("[trunc] ");
141 }
142 
143 void
144 ip6_opt_print(const u_char *bp, int len)
145 {
146     int i;
147     int optlen = 0;
148 
149     for (i = 0; i < len; i += optlen) {
150 	if (bp[i] == IP6OPT_PAD1)
151 	    optlen = 1;
152 	else {
153 	    if (i + 1 < len)
154 		optlen = bp[i + 1] + 2;
155 	    else
156 		goto trunc;
157 	}
158 	if (i + optlen > len)
159 	    goto trunc;
160 
161 	switch (bp[i]) {
162 	case IP6OPT_PAD1:
163             printf("(pad1)");
164 	    break;
165 	case IP6OPT_PADN:
166 	    if (len - i < IP6OPT_MINLEN) {
167 		printf("(padn: trunc)");
168 		goto trunc;
169 	    }
170             printf("(padn)");
171 	    break;
172 	case IP6OPT_ROUTER_ALERT:
173 	    if (len - i < IP6OPT_RTALERT_LEN) {
174 		printf("(rtalert: trunc)");
175 		goto trunc;
176 	    }
177 	    if (bp[i + 1] != IP6OPT_RTALERT_LEN - 2) {
178 		printf("(rtalert: invalid len %d)", bp[i + 1]);
179 		goto trunc;
180 	    }
181 	    printf("(rtalert: 0x%04x) ", EXTRACT_16BITS(&bp[i + 2]));
182 	    break;
183 	case IP6OPT_JUMBO:
184 	    if (len - i < IP6OPT_JUMBO_LEN) {
185 		printf("(jumbo: trunc)");
186 		goto trunc;
187 	    }
188 	    if (bp[i + 1] != IP6OPT_JUMBO_LEN - 2) {
189 		printf("(jumbo: invalid len %d)", bp[i + 1]);
190 		goto trunc;
191 	    }
192 	    printf("(jumbo: %u) ", EXTRACT_32BITS(&bp[i + 2]));
193 	    break;
194         case IP6OPT_HOME_ADDRESS:
195 	    if (len - i < IP6OPT_HOMEADDR_MINLEN) {
196 		printf("(homeaddr: trunc)");
197 		goto trunc;
198 	    }
199 	    if (bp[i + 1] < IP6OPT_HOMEADDR_MINLEN - 2) {
200 		printf("(homeaddr: invalid len %d)", bp[i + 1]);
201 		goto trunc;
202 	    }
203 	    printf("(homeaddr: %s", ip6addr_string(&bp[i + 2]));
204             if (bp[i + 1] > IP6OPT_HOMEADDR_MINLEN - 2) {
205 		ip6_sopt_print(&bp[i + IP6OPT_HOMEADDR_MINLEN],
206 		    (optlen - IP6OPT_HOMEADDR_MINLEN));
207 	    }
208             printf(")");
209 	    break;
210         case IP6OPT_BINDING_UPDATE:
211 	    if (len - i < IP6OPT_BU_MINLEN) {
212 		printf("(bu: trunc)");
213 		goto trunc;
214 	    }
215 	    if (bp[i + 1] < IP6OPT_BU_MINLEN - 2) {
216 		printf("(bu: invalid len %d)", bp[i + 1]);
217 		goto trunc;
218 	    }
219 	    printf("(bu: ");
220 	    if (bp[i + 2] & 0x80)
221 		    printf("A");
222 	    if (bp[i + 2] & 0x40)
223 		    printf("H");
224 	    if (bp[i + 2] & 0x20)
225 		    printf("S");
226 	    if (bp[i + 2] & 0x10)
227 		    printf("D");
228 	    if ((bp[i + 2] & 0x0f) || bp[i + 3] || bp[i + 4])
229 		    printf("res");
230 	    printf(", sequence: %u", bp[i + 5]);
231 	    printf(", lifetime: %u", EXTRACT_32BITS(&bp[i + 6]));
232 
233 	    if (bp[i + 1] > IP6OPT_BU_MINLEN - 2) {
234 		ip6_sopt_print(&bp[i + IP6OPT_BU_MINLEN],
235 		    (optlen - IP6OPT_BU_MINLEN));
236 	    }
237 	    printf(")");
238 	    break;
239 	case IP6OPT_BINDING_ACK:
240 	    if (len - i < IP6OPT_BA_MINLEN) {
241 		printf("(ba: trunc)");
242 		goto trunc;
243 	    }
244 	    if (bp[i + 1] < IP6OPT_BA_MINLEN - 2) {
245 		printf("(ba: invalid len %d)", bp[i + 1]);
246 		goto trunc;
247 	    }
248 	    printf("(ba: ");
249 	    printf("status: %u", bp[i + 2]);
250 	    if (bp[i + 3])
251 		    printf("res");
252 	    printf(", sequence: %u", bp[i + 4]);
253 	    printf(", lifetime: %u", EXTRACT_32BITS(&bp[i + 5]));
254 	    printf(", refresh: %u", EXTRACT_32BITS(&bp[i + 9]));
255 
256 	    if (bp[i + 1] > IP6OPT_BA_MINLEN - 2) {
257 		ip6_sopt_print(&bp[i + IP6OPT_BA_MINLEN],
258 		    (optlen - IP6OPT_BA_MINLEN));
259 	    }
260             printf(")");
261 	    break;
262         case IP6OPT_BINDING_REQ:
263 	    if (len - i < IP6OPT_BR_MINLEN) {
264 		printf("(br: trunc)");
265 		goto trunc;
266 	    }
267             printf("(br");
268             if (bp[i + 1] > IP6OPT_BR_MINLEN - 2) {
269 		ip6_sopt_print(&bp[i + IP6OPT_BR_MINLEN],
270 		    (optlen - IP6OPT_BR_MINLEN));
271 	    }
272             printf(")");
273 	    break;
274 	default:
275 	    if (len - i < IP6OPT_MINLEN) {
276 		printf("(type %d: trunc)", bp[i]);
277 		goto trunc;
278 	    }
279 	    printf("(opt_type 0x%02x: len=%d) ", bp[i], bp[i + 1]);
280 	    break;
281 	}
282     }
283 
284 #if 0
285 end:
286 #endif
287     return;
288 
289 trunc:
290     printf("[trunc] ");
291 }
292 
293 int
294 hbhopt_print(register const u_char *bp)
295 {
296     const struct ip6_hbh *dp = (struct ip6_hbh *)bp;
297     int hbhlen = 0;
298 
299     TCHECK(dp->ip6h_len);
300     hbhlen = (int)((dp->ip6h_len + 1) << 3);
301     TCHECK2(*dp, hbhlen);
302     printf("HBH ");
303     if (vflag)
304 	ip6_opt_print((const u_char *)dp + sizeof(*dp), hbhlen - sizeof(*dp));
305 
306     return(hbhlen);
307 
308   trunc:
309     fputs("[|HBH]", stdout);
310     return(-1);
311 }
312 
313 int
314 dstopt_print(register const u_char *bp)
315 {
316     const struct ip6_dest *dp = (struct ip6_dest *)bp;
317     int dstoptlen = 0;
318 
319     TCHECK(dp->ip6d_len);
320     dstoptlen = (int)((dp->ip6d_len + 1) << 3);
321     TCHECK2(*dp, dstoptlen);
322     printf("DSTOPT ");
323     if (vflag) {
324 	ip6_opt_print((const u_char *)dp + sizeof(*dp),
325 	    dstoptlen - sizeof(*dp));
326     }
327 
328     return(dstoptlen);
329 
330   trunc:
331     fputs("[|DSTOPT]", stdout);
332     return(-1);
333 }
334 #endif /* INET6 */
335