1*05b00f60SXin Li /*
2*05b00f60SXin Li * Copyright (C) 1998 WIDE Project.
3*05b00f60SXin Li * All rights reserved.
4*05b00f60SXin Li *
5*05b00f60SXin Li * Redistribution and use in source and binary forms, with or without
6*05b00f60SXin Li * modification, are permitted provided that the following conditions
7*05b00f60SXin Li * are met:
8*05b00f60SXin Li * 1. Redistributions of source code must retain the above copyright
9*05b00f60SXin Li * notice, this list of conditions and the following disclaimer.
10*05b00f60SXin Li * 2. Redistributions in binary form must reproduce the above copyright
11*05b00f60SXin Li * notice, this list of conditions and the following disclaimer in the
12*05b00f60SXin Li * documentation and/or other materials provided with the distribution.
13*05b00f60SXin Li * 3. Neither the name of the project nor the names of its contributors
14*05b00f60SXin Li * may be used to endorse or promote products derived from this software
15*05b00f60SXin Li * without specific prior written permission.
16*05b00f60SXin Li *
17*05b00f60SXin Li * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18*05b00f60SXin Li * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*05b00f60SXin Li * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*05b00f60SXin Li * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21*05b00f60SXin Li * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*05b00f60SXin Li * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*05b00f60SXin Li * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*05b00f60SXin Li * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*05b00f60SXin Li * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*05b00f60SXin Li * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*05b00f60SXin Li * SUCH DAMAGE.
28*05b00f60SXin Li */
29*05b00f60SXin Li
30*05b00f60SXin Li /* \summary: IPv6 header option printer */
31*05b00f60SXin Li
32*05b00f60SXin Li #ifdef HAVE_CONFIG_H
33*05b00f60SXin Li #include <config.h>
34*05b00f60SXin Li #endif
35*05b00f60SXin Li
36*05b00f60SXin Li #include "netdissect-stdinc.h"
37*05b00f60SXin Li
38*05b00f60SXin Li #include "netdissect.h"
39*05b00f60SXin Li #include "addrtoname.h"
40*05b00f60SXin Li #include "extract.h"
41*05b00f60SXin Li
42*05b00f60SXin Li #include "ip6.h"
43*05b00f60SXin Li
44*05b00f60SXin Li static int
ip6_sopt_print(netdissect_options * ndo,const u_char * bp,int len)45*05b00f60SXin Li ip6_sopt_print(netdissect_options *ndo, const u_char *bp, int len)
46*05b00f60SXin Li {
47*05b00f60SXin Li int i;
48*05b00f60SXin Li int optlen;
49*05b00f60SXin Li
50*05b00f60SXin Li for (i = 0; i < len; i += optlen) {
51*05b00f60SXin Li if (GET_U_1(bp + i) == IP6OPT_PAD1)
52*05b00f60SXin Li optlen = 1;
53*05b00f60SXin Li else {
54*05b00f60SXin Li if (i + 1 < len)
55*05b00f60SXin Li optlen = GET_U_1(bp + i + 1) + 2;
56*05b00f60SXin Li else
57*05b00f60SXin Li goto trunc;
58*05b00f60SXin Li }
59*05b00f60SXin Li if (i + optlen > len)
60*05b00f60SXin Li goto trunc;
61*05b00f60SXin Li
62*05b00f60SXin Li switch (GET_U_1(bp + i)) {
63*05b00f60SXin Li case IP6OPT_PAD1:
64*05b00f60SXin Li ND_PRINT(", pad1");
65*05b00f60SXin Li break;
66*05b00f60SXin Li case IP6OPT_PADN:
67*05b00f60SXin Li if (len - i < IP6OPT_MINLEN) {
68*05b00f60SXin Li ND_PRINT(", padn: trunc");
69*05b00f60SXin Li goto trunc;
70*05b00f60SXin Li }
71*05b00f60SXin Li ND_PRINT(", padn");
72*05b00f60SXin Li break;
73*05b00f60SXin Li default:
74*05b00f60SXin Li if (len - i < IP6OPT_MINLEN) {
75*05b00f60SXin Li ND_PRINT(", sopt_type %u: trunc)", GET_U_1(bp + i));
76*05b00f60SXin Li goto trunc;
77*05b00f60SXin Li }
78*05b00f60SXin Li ND_PRINT(", sopt_type 0x%02x: len=%u", GET_U_1(bp + i),
79*05b00f60SXin Li GET_U_1(bp + i + 1));
80*05b00f60SXin Li break;
81*05b00f60SXin Li }
82*05b00f60SXin Li }
83*05b00f60SXin Li return 0;
84*05b00f60SXin Li
85*05b00f60SXin Li trunc:
86*05b00f60SXin Li return -1;
87*05b00f60SXin Li }
88*05b00f60SXin Li
89*05b00f60SXin Li static int
ip6_opt_process(netdissect_options * ndo,const u_char * bp,int len,int * found_jumbop,uint32_t * payload_len)90*05b00f60SXin Li ip6_opt_process(netdissect_options *ndo, const u_char *bp, int len,
91*05b00f60SXin Li int *found_jumbop, uint32_t *payload_len)
92*05b00f60SXin Li {
93*05b00f60SXin Li int i;
94*05b00f60SXin Li int optlen = 0;
95*05b00f60SXin Li int found_jumbo = 0;
96*05b00f60SXin Li uint32_t jumbolen = 0;
97*05b00f60SXin Li
98*05b00f60SXin Li if (len == 0)
99*05b00f60SXin Li return 0;
100*05b00f60SXin Li for (i = 0; i < len; i += optlen) {
101*05b00f60SXin Li if (GET_U_1(bp + i) == IP6OPT_PAD1)
102*05b00f60SXin Li optlen = 1;
103*05b00f60SXin Li else {
104*05b00f60SXin Li if (i + 1 < len)
105*05b00f60SXin Li optlen = GET_U_1(bp + i + 1) + 2;
106*05b00f60SXin Li else
107*05b00f60SXin Li goto trunc;
108*05b00f60SXin Li }
109*05b00f60SXin Li if (i + optlen > len)
110*05b00f60SXin Li goto trunc;
111*05b00f60SXin Li
112*05b00f60SXin Li switch (GET_U_1(bp + i)) {
113*05b00f60SXin Li case IP6OPT_PAD1:
114*05b00f60SXin Li if (ndo->ndo_vflag)
115*05b00f60SXin Li ND_PRINT("(pad1)");
116*05b00f60SXin Li break;
117*05b00f60SXin Li case IP6OPT_PADN:
118*05b00f60SXin Li if (len - i < IP6OPT_MINLEN) {
119*05b00f60SXin Li ND_PRINT("(padn: trunc)");
120*05b00f60SXin Li goto trunc;
121*05b00f60SXin Li }
122*05b00f60SXin Li if (ndo->ndo_vflag)
123*05b00f60SXin Li ND_PRINT("(padn)");
124*05b00f60SXin Li break;
125*05b00f60SXin Li case IP6OPT_ROUTER_ALERT:
126*05b00f60SXin Li if (len - i < IP6OPT_RTALERT_LEN) {
127*05b00f60SXin Li ND_PRINT("(rtalert: trunc)");
128*05b00f60SXin Li goto trunc;
129*05b00f60SXin Li }
130*05b00f60SXin Li if (GET_U_1(bp + i + 1) != IP6OPT_RTALERT_LEN - 2) {
131*05b00f60SXin Li ND_PRINT("(rtalert: invalid len %u)", GET_U_1(bp + i + 1));
132*05b00f60SXin Li goto trunc;
133*05b00f60SXin Li }
134*05b00f60SXin Li if (ndo->ndo_vflag)
135*05b00f60SXin Li ND_PRINT("(rtalert: 0x%04x) ", GET_BE_U_2(bp + i + 2));
136*05b00f60SXin Li break;
137*05b00f60SXin Li case IP6OPT_JUMBO:
138*05b00f60SXin Li if (len - i < IP6OPT_JUMBO_LEN) {
139*05b00f60SXin Li ND_PRINT("(jumbo: trunc)");
140*05b00f60SXin Li goto trunc;
141*05b00f60SXin Li }
142*05b00f60SXin Li if (GET_U_1(bp + i + 1) != IP6OPT_JUMBO_LEN - 2) {
143*05b00f60SXin Li ND_PRINT("(jumbo: invalid len %u)", GET_U_1(bp + i + 1));
144*05b00f60SXin Li goto trunc;
145*05b00f60SXin Li }
146*05b00f60SXin Li jumbolen = GET_BE_U_4(bp + i + 2);
147*05b00f60SXin Li if (found_jumbo) {
148*05b00f60SXin Li /* More than one Jumbo Payload option */
149*05b00f60SXin Li if (ndo->ndo_vflag)
150*05b00f60SXin Li ND_PRINT("(jumbo: %u - already seen) ", jumbolen);
151*05b00f60SXin Li } else {
152*05b00f60SXin Li found_jumbo = 1;
153*05b00f60SXin Li if (payload_len == NULL) {
154*05b00f60SXin Li /* Not a hop-by-hop option - not valid */
155*05b00f60SXin Li if (ndo->ndo_vflag)
156*05b00f60SXin Li ND_PRINT("(jumbo: %u - not a hop-by-hop option) ", jumbolen);
157*05b00f60SXin Li } else if (*payload_len != 0) {
158*05b00f60SXin Li /* Payload length was non-zero - not valid */
159*05b00f60SXin Li if (ndo->ndo_vflag)
160*05b00f60SXin Li ND_PRINT("(jumbo: %u - payload len != 0) ", jumbolen);
161*05b00f60SXin Li } else {
162*05b00f60SXin Li /*
163*05b00f60SXin Li * This is a hop-by-hop option, and Payload length
164*05b00f60SXin Li * was zero in the IPv6 header.
165*05b00f60SXin Li */
166*05b00f60SXin Li if (jumbolen < 65536) {
167*05b00f60SXin Li /* Too short */
168*05b00f60SXin Li if (ndo->ndo_vflag)
169*05b00f60SXin Li ND_PRINT("(jumbo: %u - < 65536) ", jumbolen);
170*05b00f60SXin Li } else {
171*05b00f60SXin Li /* OK, this is valid */
172*05b00f60SXin Li *found_jumbop = 1;
173*05b00f60SXin Li *payload_len = jumbolen;
174*05b00f60SXin Li if (ndo->ndo_vflag)
175*05b00f60SXin Li ND_PRINT("(jumbo: %u) ", jumbolen);
176*05b00f60SXin Li }
177*05b00f60SXin Li }
178*05b00f60SXin Li }
179*05b00f60SXin Li break;
180*05b00f60SXin Li case IP6OPT_HOME_ADDRESS:
181*05b00f60SXin Li if (len - i < IP6OPT_HOMEADDR_MINLEN) {
182*05b00f60SXin Li ND_PRINT("(homeaddr: trunc)");
183*05b00f60SXin Li goto trunc;
184*05b00f60SXin Li }
185*05b00f60SXin Li if (GET_U_1(bp + i + 1) < IP6OPT_HOMEADDR_MINLEN - 2) {
186*05b00f60SXin Li ND_PRINT("(homeaddr: invalid len %u)", GET_U_1(bp + i + 1));
187*05b00f60SXin Li goto trunc;
188*05b00f60SXin Li }
189*05b00f60SXin Li if (ndo->ndo_vflag) {
190*05b00f60SXin Li ND_PRINT("(homeaddr: %s", GET_IP6ADDR_STRING(bp + i + 2));
191*05b00f60SXin Li if (GET_U_1(bp + i + 1) > IP6OPT_HOMEADDR_MINLEN - 2) {
192*05b00f60SXin Li if (ip6_sopt_print(ndo, bp + i + IP6OPT_HOMEADDR_MINLEN,
193*05b00f60SXin Li (optlen - IP6OPT_HOMEADDR_MINLEN)) == -1)
194*05b00f60SXin Li goto trunc;
195*05b00f60SXin Li }
196*05b00f60SXin Li ND_PRINT(")");
197*05b00f60SXin Li }
198*05b00f60SXin Li break;
199*05b00f60SXin Li default:
200*05b00f60SXin Li if (len - i < IP6OPT_MINLEN) {
201*05b00f60SXin Li ND_PRINT("(type %u: trunc)", GET_U_1(bp + i));
202*05b00f60SXin Li goto trunc;
203*05b00f60SXin Li }
204*05b00f60SXin Li if (ndo->ndo_vflag)
205*05b00f60SXin Li ND_PRINT("(opt_type 0x%02x: len=%u)", GET_U_1(bp + i),
206*05b00f60SXin Li GET_U_1(bp + i + 1));
207*05b00f60SXin Li break;
208*05b00f60SXin Li }
209*05b00f60SXin Li }
210*05b00f60SXin Li if (ndo->ndo_vflag)
211*05b00f60SXin Li ND_PRINT(" ");
212*05b00f60SXin Li return 0;
213*05b00f60SXin Li
214*05b00f60SXin Li trunc:
215*05b00f60SXin Li return -1;
216*05b00f60SXin Li }
217*05b00f60SXin Li
218*05b00f60SXin Li int
hbhopt_process(netdissect_options * ndo,const u_char * bp,int * found_jumbo,uint32_t * jumbolen)219*05b00f60SXin Li hbhopt_process(netdissect_options *ndo, const u_char *bp, int *found_jumbo,
220*05b00f60SXin Li uint32_t *jumbolen)
221*05b00f60SXin Li {
222*05b00f60SXin Li const struct ip6_hbh *dp = (const struct ip6_hbh *)bp;
223*05b00f60SXin Li u_int hbhlen = 0;
224*05b00f60SXin Li
225*05b00f60SXin Li ndo->ndo_protocol = "hbhopt";
226*05b00f60SXin Li hbhlen = (GET_U_1(dp->ip6h_len) + 1) << 3;
227*05b00f60SXin Li ND_TCHECK_LEN(dp, hbhlen);
228*05b00f60SXin Li ND_PRINT("HBH ");
229*05b00f60SXin Li if (ip6_opt_process(ndo, (const u_char *)dp + sizeof(*dp),
230*05b00f60SXin Li hbhlen - sizeof(*dp), found_jumbo, jumbolen) == -1)
231*05b00f60SXin Li goto trunc;
232*05b00f60SXin Li return hbhlen;
233*05b00f60SXin Li
234*05b00f60SXin Li trunc:
235*05b00f60SXin Li nd_print_trunc(ndo);
236*05b00f60SXin Li return -1;
237*05b00f60SXin Li }
238*05b00f60SXin Li
239*05b00f60SXin Li int
dstopt_process(netdissect_options * ndo,const u_char * bp)240*05b00f60SXin Li dstopt_process(netdissect_options *ndo, const u_char *bp)
241*05b00f60SXin Li {
242*05b00f60SXin Li const struct ip6_dest *dp = (const struct ip6_dest *)bp;
243*05b00f60SXin Li u_int dstoptlen = 0;
244*05b00f60SXin Li
245*05b00f60SXin Li ndo->ndo_protocol = "dstopt";
246*05b00f60SXin Li dstoptlen = (GET_U_1(dp->ip6d_len) + 1) << 3;
247*05b00f60SXin Li ND_TCHECK_LEN(dp, dstoptlen);
248*05b00f60SXin Li ND_PRINT("DSTOPT ");
249*05b00f60SXin Li if (ndo->ndo_vflag) {
250*05b00f60SXin Li /*
251*05b00f60SXin Li * The Jumbo Payload option is a hop-by-hop option; we don't
252*05b00f60SXin Li * honor Jumbo Payload destination options, reporting them
253*05b00f60SXin Li * as invalid.
254*05b00f60SXin Li */
255*05b00f60SXin Li if (ip6_opt_process(ndo, (const u_char *)dp + sizeof(*dp),
256*05b00f60SXin Li dstoptlen - sizeof(*dp), NULL, NULL) == -1)
257*05b00f60SXin Li goto trunc;
258*05b00f60SXin Li }
259*05b00f60SXin Li
260*05b00f60SXin Li return dstoptlen;
261*05b00f60SXin Li
262*05b00f60SXin Li trunc:
263*05b00f60SXin Li nd_print_trunc(ndo);
264*05b00f60SXin Li return -1;
265*05b00f60SXin Li }
266