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