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