xref: /netbsd-src/external/bsd/tcpdump/dist/print-ip6opts.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
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.3 2013/04/06 19:33:08 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     if (len == 0)
150         return;
151     for (i = 0; i < len; i += optlen) {
152 	if (bp[i] == IP6OPT_PAD1)
153 	    optlen = 1;
154 	else {
155 	    if (i + 1 < len)
156 		optlen = bp[i + 1] + 2;
157 	    else
158 		goto trunc;
159 	}
160 	if (i + optlen > len)
161 	    goto trunc;
162 
163 	switch (bp[i]) {
164 	case IP6OPT_PAD1:
165             printf("(pad1)");
166 	    break;
167 	case IP6OPT_PADN:
168 	    if (len - i < IP6OPT_MINLEN) {
169 		printf("(padn: trunc)");
170 		goto trunc;
171 	    }
172             printf("(padn)");
173 	    break;
174 	case IP6OPT_ROUTER_ALERT:
175 	    if (len - i < IP6OPT_RTALERT_LEN) {
176 		printf("(rtalert: trunc)");
177 		goto trunc;
178 	    }
179 	    if (bp[i + 1] != IP6OPT_RTALERT_LEN - 2) {
180 		printf("(rtalert: invalid len %d)", bp[i + 1]);
181 		goto trunc;
182 	    }
183 	    printf("(rtalert: 0x%04x) ", EXTRACT_16BITS(&bp[i + 2]));
184 	    break;
185 	case IP6OPT_JUMBO:
186 	    if (len - i < IP6OPT_JUMBO_LEN) {
187 		printf("(jumbo: trunc)");
188 		goto trunc;
189 	    }
190 	    if (bp[i + 1] != IP6OPT_JUMBO_LEN - 2) {
191 		printf("(jumbo: invalid len %d)", bp[i + 1]);
192 		goto trunc;
193 	    }
194 	    printf("(jumbo: %u) ", EXTRACT_32BITS(&bp[i + 2]));
195 	    break;
196         case IP6OPT_HOME_ADDRESS:
197 	    if (len - i < IP6OPT_HOMEADDR_MINLEN) {
198 		printf("(homeaddr: trunc)");
199 		goto trunc;
200 	    }
201 	    if (bp[i + 1] < IP6OPT_HOMEADDR_MINLEN - 2) {
202 		printf("(homeaddr: invalid len %d)", bp[i + 1]);
203 		goto trunc;
204 	    }
205 	    printf("(homeaddr: %s", ip6addr_string(&bp[i + 2]));
206             if (bp[i + 1] > IP6OPT_HOMEADDR_MINLEN - 2) {
207 		ip6_sopt_print(&bp[i + IP6OPT_HOMEADDR_MINLEN],
208 		    (optlen - IP6OPT_HOMEADDR_MINLEN));
209 	    }
210             printf(")");
211 	    break;
212         case IP6OPT_BINDING_UPDATE:
213 	    if (len - i < IP6OPT_BU_MINLEN) {
214 		printf("(bu: trunc)");
215 		goto trunc;
216 	    }
217 	    if (bp[i + 1] < IP6OPT_BU_MINLEN - 2) {
218 		printf("(bu: invalid len %d)", bp[i + 1]);
219 		goto trunc;
220 	    }
221 	    printf("(bu: ");
222 	    if (bp[i + 2] & 0x80)
223 		    printf("A");
224 	    if (bp[i + 2] & 0x40)
225 		    printf("H");
226 	    if (bp[i + 2] & 0x20)
227 		    printf("S");
228 	    if (bp[i + 2] & 0x10)
229 		    printf("D");
230 	    if ((bp[i + 2] & 0x0f) || bp[i + 3] || bp[i + 4])
231 		    printf("res");
232 	    printf(", sequence: %u", bp[i + 5]);
233 	    printf(", lifetime: %u", EXTRACT_32BITS(&bp[i + 6]));
234 
235 	    if (bp[i + 1] > IP6OPT_BU_MINLEN - 2) {
236 		ip6_sopt_print(&bp[i + IP6OPT_BU_MINLEN],
237 		    (optlen - IP6OPT_BU_MINLEN));
238 	    }
239 	    printf(")");
240 	    break;
241 	case IP6OPT_BINDING_ACK:
242 	    if (len - i < IP6OPT_BA_MINLEN) {
243 		printf("(ba: trunc)");
244 		goto trunc;
245 	    }
246 	    if (bp[i + 1] < IP6OPT_BA_MINLEN - 2) {
247 		printf("(ba: invalid len %d)", bp[i + 1]);
248 		goto trunc;
249 	    }
250 	    printf("(ba: ");
251 	    printf("status: %u", bp[i + 2]);
252 	    if (bp[i + 3])
253 		    printf("res");
254 	    printf(", sequence: %u", bp[i + 4]);
255 	    printf(", lifetime: %u", EXTRACT_32BITS(&bp[i + 5]));
256 	    printf(", refresh: %u", EXTRACT_32BITS(&bp[i + 9]));
257 
258 	    if (bp[i + 1] > IP6OPT_BA_MINLEN - 2) {
259 		ip6_sopt_print(&bp[i + IP6OPT_BA_MINLEN],
260 		    (optlen - IP6OPT_BA_MINLEN));
261 	    }
262             printf(")");
263 	    break;
264         case IP6OPT_BINDING_REQ:
265 	    if (len - i < IP6OPT_BR_MINLEN) {
266 		printf("(br: trunc)");
267 		goto trunc;
268 	    }
269             printf("(br");
270             if (bp[i + 1] > IP6OPT_BR_MINLEN - 2) {
271 		ip6_sopt_print(&bp[i + IP6OPT_BR_MINLEN],
272 		    (optlen - IP6OPT_BR_MINLEN));
273 	    }
274             printf(")");
275 	    break;
276 	default:
277 	    if (len - i < IP6OPT_MINLEN) {
278 		printf("(type %d: trunc)", bp[i]);
279 		goto trunc;
280 	    }
281 	    printf("(opt_type 0x%02x: len=%d)", bp[i], bp[i + 1]);
282 	    break;
283 	}
284     }
285     printf(" ");
286 
287 #if 0
288 end:
289 #endif
290     return;
291 
292 trunc:
293     printf("[trunc] ");
294 }
295 
296 int
297 hbhopt_print(register const u_char *bp)
298 {
299     const struct ip6_hbh *dp = (struct ip6_hbh *)bp;
300     int hbhlen = 0;
301 
302     TCHECK(dp->ip6h_len);
303     hbhlen = (int)((dp->ip6h_len + 1) << 3);
304     TCHECK2(*dp, hbhlen);
305     printf("HBH ");
306     if (vflag)
307 	ip6_opt_print((const u_char *)dp + sizeof(*dp), hbhlen - sizeof(*dp));
308 
309     return(hbhlen);
310 
311   trunc:
312     fputs("[|HBH]", stdout);
313     return(-1);
314 }
315 
316 int
317 dstopt_print(register const u_char *bp)
318 {
319     const struct ip6_dest *dp = (struct ip6_dest *)bp;
320     int dstoptlen = 0;
321 
322     TCHECK(dp->ip6d_len);
323     dstoptlen = (int)((dp->ip6d_len + 1) << 3);
324     TCHECK2(*dp, dstoptlen);
325     printf("DSTOPT ");
326     if (vflag) {
327 	ip6_opt_print((const u_char *)dp + sizeof(*dp),
328 	    dstoptlen - sizeof(*dp));
329     }
330 
331     return(dstoptlen);
332 
333   trunc:
334     fputs("[|DSTOPT]", stdout);
335     return(-1);
336 }
337 #endif /* INET6 */
338