xref: /freebsd/contrib/tcpdump/print-ip6opts.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
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