141c99275SPeter Avalos /*
241c99275SPeter Avalos * Copyright (C) 2002 WIDE Project.
341c99275SPeter Avalos * All rights reserved.
441c99275SPeter Avalos *
541c99275SPeter Avalos * Redistribution and use in source and binary forms, with or without
641c99275SPeter Avalos * modification, are permitted provided that the following conditions
741c99275SPeter Avalos * are met:
841c99275SPeter Avalos * 1. Redistributions of source code must retain the above copyright
941c99275SPeter Avalos * notice, this list of conditions and the following disclaimer.
1041c99275SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright
1141c99275SPeter Avalos * notice, this list of conditions and the following disclaimer in the
1241c99275SPeter Avalos * documentation and/or other materials provided with the distribution.
1341c99275SPeter Avalos * 3. Neither the name of the project nor the names of its contributors
1441c99275SPeter Avalos * may be used to endorse or promote products derived from this software
1541c99275SPeter Avalos * without specific prior written permission.
1641c99275SPeter Avalos *
1741c99275SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1841c99275SPeter Avalos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1941c99275SPeter Avalos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2041c99275SPeter Avalos * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2141c99275SPeter Avalos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2241c99275SPeter Avalos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2341c99275SPeter Avalos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2441c99275SPeter Avalos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2541c99275SPeter Avalos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2641c99275SPeter Avalos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2741c99275SPeter Avalos * SUCH DAMAGE.
2841c99275SPeter Avalos */
2941c99275SPeter Avalos
30411677aeSAaron LI /* \summary: IPv6 mobility printer */
31411677aeSAaron LI /* RFC 3775 */
32411677aeSAaron LI
3341c99275SPeter Avalos #ifdef HAVE_CONFIG_H
34*ed775ee7SAntonio Huete Jimenez #include <config.h>
3541c99275SPeter Avalos #endif
3641c99275SPeter Avalos
37*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
3841c99275SPeter Avalos
39411677aeSAaron LI #include "netdissect.h"
40411677aeSAaron LI #include "addrtoname.h"
41411677aeSAaron LI #include "extract.h"
4241c99275SPeter Avalos
4341c99275SPeter Avalos #include "ip6.h"
4441c99275SPeter Avalos
4541c99275SPeter Avalos
4641c99275SPeter Avalos /* Mobility header */
4741c99275SPeter Avalos struct ip6_mobility {
48*ed775ee7SAntonio Huete Jimenez nd_uint8_t ip6m_pproto; /* following payload protocol (for PG) */
49*ed775ee7SAntonio Huete Jimenez nd_uint8_t ip6m_len; /* length in units of 8 octets */
50*ed775ee7SAntonio Huete Jimenez nd_uint8_t ip6m_type; /* message type */
51*ed775ee7SAntonio Huete Jimenez nd_uint8_t reserved; /* reserved */
52*ed775ee7SAntonio Huete Jimenez nd_uint16_t ip6m_cksum; /* sum of IPv6 pseudo-header and MH */
5341c99275SPeter Avalos union {
54*ed775ee7SAntonio Huete Jimenez nd_uint16_t ip6m_un_data16[1]; /* type-specific field */
55*ed775ee7SAntonio Huete Jimenez nd_uint8_t ip6m_un_data8[2]; /* type-specific field */
5641c99275SPeter Avalos } ip6m_dataun;
5741c99275SPeter Avalos };
5841c99275SPeter Avalos
5941c99275SPeter Avalos #define ip6m_data16 ip6m_dataun.ip6m_un_data16
6041c99275SPeter Avalos #define ip6m_data8 ip6m_dataun.ip6m_un_data8
6141c99275SPeter Avalos
6241c99275SPeter Avalos #define IP6M_MINLEN 8
6341c99275SPeter Avalos
64*ed775ee7SAntonio Huete Jimenez /* https://www.iana.org/assignments/mobility-parameters/mobility-parameters.xhtml */
65411677aeSAaron LI
6641c99275SPeter Avalos /* message type */
6741c99275SPeter Avalos #define IP6M_BINDING_REQUEST 0 /* Binding Refresh Request */
6841c99275SPeter Avalos #define IP6M_HOME_TEST_INIT 1 /* Home Test Init */
6941c99275SPeter Avalos #define IP6M_CAREOF_TEST_INIT 2 /* Care-of Test Init */
7041c99275SPeter Avalos #define IP6M_HOME_TEST 3 /* Home Test */
7141c99275SPeter Avalos #define IP6M_CAREOF_TEST 4 /* Care-of Test */
7241c99275SPeter Avalos #define IP6M_BINDING_UPDATE 5 /* Binding Update */
7341c99275SPeter Avalos #define IP6M_BINDING_ACK 6 /* Binding Acknowledgement */
7441c99275SPeter Avalos #define IP6M_BINDING_ERROR 7 /* Binding Error */
75411677aeSAaron LI #define IP6M_MAX 7
76411677aeSAaron LI
77411677aeSAaron LI static const struct tok ip6m_str[] = {
78411677aeSAaron LI { IP6M_BINDING_REQUEST, "BRR" },
79411677aeSAaron LI { IP6M_HOME_TEST_INIT, "HoTI" },
80411677aeSAaron LI { IP6M_CAREOF_TEST_INIT, "CoTI" },
81411677aeSAaron LI { IP6M_HOME_TEST, "HoT" },
82411677aeSAaron LI { IP6M_CAREOF_TEST, "CoT" },
83411677aeSAaron LI { IP6M_BINDING_UPDATE, "BU" },
84411677aeSAaron LI { IP6M_BINDING_ACK, "BA" },
85411677aeSAaron LI { IP6M_BINDING_ERROR, "BE" },
86411677aeSAaron LI { 0, NULL }
87411677aeSAaron LI };
88411677aeSAaron LI
89411677aeSAaron LI static const unsigned ip6m_hdrlen[IP6M_MAX + 1] = {
90411677aeSAaron LI IP6M_MINLEN, /* IP6M_BINDING_REQUEST */
91411677aeSAaron LI IP6M_MINLEN + 8, /* IP6M_HOME_TEST_INIT */
92411677aeSAaron LI IP6M_MINLEN + 8, /* IP6M_CAREOF_TEST_INIT */
93411677aeSAaron LI IP6M_MINLEN + 16, /* IP6M_HOME_TEST */
94411677aeSAaron LI IP6M_MINLEN + 16, /* IP6M_CAREOF_TEST */
95411677aeSAaron LI IP6M_MINLEN + 4, /* IP6M_BINDING_UPDATE */
96411677aeSAaron LI IP6M_MINLEN + 4, /* IP6M_BINDING_ACK */
97411677aeSAaron LI IP6M_MINLEN + 16, /* IP6M_BINDING_ERROR */
98411677aeSAaron LI };
9941c99275SPeter Avalos
10041c99275SPeter Avalos /* Mobility Header Options */
10141c99275SPeter Avalos #define IP6MOPT_MINLEN 2
10241c99275SPeter Avalos #define IP6MOPT_PAD1 0x0 /* Pad1 */
10341c99275SPeter Avalos #define IP6MOPT_PADN 0x1 /* PadN */
10441c99275SPeter Avalos #define IP6MOPT_REFRESH 0x2 /* Binding Refresh Advice */
10541c99275SPeter Avalos #define IP6MOPT_REFRESH_MINLEN 4
10641c99275SPeter Avalos #define IP6MOPT_ALTCOA 0x3 /* Alternate Care-of Address */
10741c99275SPeter Avalos #define IP6MOPT_ALTCOA_MINLEN 18
10841c99275SPeter Avalos #define IP6MOPT_NONCEID 0x4 /* Nonce Indices */
10941c99275SPeter Avalos #define IP6MOPT_NONCEID_MINLEN 6
11041c99275SPeter Avalos #define IP6MOPT_AUTH 0x5 /* Binding Authorization Data */
11141c99275SPeter Avalos #define IP6MOPT_AUTH_MINLEN 12
11241c99275SPeter Avalos
113*ed775ee7SAntonio Huete Jimenez static const struct tok ip6m_binding_update_bits [] = {
114*ed775ee7SAntonio Huete Jimenez { 0x08, "A" },
115*ed775ee7SAntonio Huete Jimenez { 0x04, "H" },
116*ed775ee7SAntonio Huete Jimenez { 0x02, "L" },
117*ed775ee7SAntonio Huete Jimenez { 0x01, "K" },
118*ed775ee7SAntonio Huete Jimenez { 0, NULL }
119*ed775ee7SAntonio Huete Jimenez };
120*ed775ee7SAntonio Huete Jimenez
121411677aeSAaron LI static int
mobility_opt_print(netdissect_options * ndo,const u_char * bp,const unsigned len)122411677aeSAaron LI mobility_opt_print(netdissect_options *ndo,
123411677aeSAaron LI const u_char *bp, const unsigned len)
12441c99275SPeter Avalos {
125411677aeSAaron LI unsigned i, optlen;
12641c99275SPeter Avalos
12741c99275SPeter Avalos for (i = 0; i < len; i += optlen) {
128*ed775ee7SAntonio Huete Jimenez if (GET_U_1(bp + i) == IP6MOPT_PAD1)
12941c99275SPeter Avalos optlen = 1;
13041c99275SPeter Avalos else {
131411677aeSAaron LI if (i + 1 < len) {
132*ed775ee7SAntonio Huete Jimenez optlen = GET_U_1(bp + i + 1) + 2;
133411677aeSAaron LI }
13441c99275SPeter Avalos else
13541c99275SPeter Avalos goto trunc;
13641c99275SPeter Avalos }
13741c99275SPeter Avalos if (i + optlen > len)
13841c99275SPeter Avalos goto trunc;
139*ed775ee7SAntonio Huete Jimenez ND_TCHECK_1(bp + i + optlen);
14041c99275SPeter Avalos
141*ed775ee7SAntonio Huete Jimenez switch (GET_U_1(bp + i)) {
14241c99275SPeter Avalos case IP6MOPT_PAD1:
143*ed775ee7SAntonio Huete Jimenez ND_PRINT("(pad1)");
14441c99275SPeter Avalos break;
14541c99275SPeter Avalos case IP6MOPT_PADN:
14641c99275SPeter Avalos if (len - i < IP6MOPT_MINLEN) {
147*ed775ee7SAntonio Huete Jimenez ND_PRINT("(padn: trunc)");
14841c99275SPeter Avalos goto trunc;
14941c99275SPeter Avalos }
150*ed775ee7SAntonio Huete Jimenez ND_PRINT("(padn)");
15141c99275SPeter Avalos break;
15241c99275SPeter Avalos case IP6MOPT_REFRESH:
15341c99275SPeter Avalos if (len - i < IP6MOPT_REFRESH_MINLEN) {
154*ed775ee7SAntonio Huete Jimenez ND_PRINT("(refresh: trunc)");
15541c99275SPeter Avalos goto trunc;
15641c99275SPeter Avalos }
15741c99275SPeter Avalos /* units of 4 secs */
158*ed775ee7SAntonio Huete Jimenez ND_PRINT("(refresh: %u)",
159*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(bp + i + 2) << 2);
16041c99275SPeter Avalos break;
16141c99275SPeter Avalos case IP6MOPT_ALTCOA:
16241c99275SPeter Avalos if (len - i < IP6MOPT_ALTCOA_MINLEN) {
163*ed775ee7SAntonio Huete Jimenez ND_PRINT("(altcoa: trunc)");
16441c99275SPeter Avalos goto trunc;
16541c99275SPeter Avalos }
166*ed775ee7SAntonio Huete Jimenez ND_PRINT("(alt-CoA: %s)", GET_IP6ADDR_STRING(bp + i + 2));
16741c99275SPeter Avalos break;
16841c99275SPeter Avalos case IP6MOPT_NONCEID:
16941c99275SPeter Avalos if (len - i < IP6MOPT_NONCEID_MINLEN) {
170*ed775ee7SAntonio Huete Jimenez ND_PRINT("(ni: trunc)");
17141c99275SPeter Avalos goto trunc;
17241c99275SPeter Avalos }
173*ed775ee7SAntonio Huete Jimenez ND_PRINT("(ni: ho=0x%04x co=0x%04x)",
174*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(bp + i + 2),
175*ed775ee7SAntonio Huete Jimenez GET_BE_U_2(bp + i + 4));
17641c99275SPeter Avalos break;
17741c99275SPeter Avalos case IP6MOPT_AUTH:
17841c99275SPeter Avalos if (len - i < IP6MOPT_AUTH_MINLEN) {
179*ed775ee7SAntonio Huete Jimenez ND_PRINT("(auth: trunc)");
18041c99275SPeter Avalos goto trunc;
18141c99275SPeter Avalos }
182*ed775ee7SAntonio Huete Jimenez ND_PRINT("(auth)");
18341c99275SPeter Avalos break;
18441c99275SPeter Avalos default:
18541c99275SPeter Avalos if (len - i < IP6MOPT_MINLEN) {
186*ed775ee7SAntonio Huete Jimenez ND_PRINT("(sopt_type %u: trunc)",
187*ed775ee7SAntonio Huete Jimenez GET_U_1(bp + i));
18841c99275SPeter Avalos goto trunc;
18941c99275SPeter Avalos }
190*ed775ee7SAntonio Huete Jimenez ND_PRINT("(type-0x%02x: len=%u)", GET_U_1(bp + i),
191*ed775ee7SAntonio Huete Jimenez GET_U_1(bp + i + 1));
19241c99275SPeter Avalos break;
19341c99275SPeter Avalos }
19441c99275SPeter Avalos }
195411677aeSAaron LI return 0;
19641c99275SPeter Avalos
19741c99275SPeter Avalos trunc:
198411677aeSAaron LI return 1;
19941c99275SPeter Avalos }
20041c99275SPeter Avalos
20141c99275SPeter Avalos /*
20241c99275SPeter Avalos * Mobility Header
20341c99275SPeter Avalos */
20441c99275SPeter Avalos int
mobility_print(netdissect_options * ndo,const u_char * bp,const u_char * bp2 _U_)205411677aeSAaron LI mobility_print(netdissect_options *ndo,
206411677aeSAaron LI const u_char *bp, const u_char *bp2 _U_)
20741c99275SPeter Avalos {
20841c99275SPeter Avalos const struct ip6_mobility *mh;
20941c99275SPeter Avalos const u_char *ep;
210411677aeSAaron LI unsigned mhlen, hlen;
211411677aeSAaron LI uint8_t type;
21241c99275SPeter Avalos
213*ed775ee7SAntonio Huete Jimenez ndo->ndo_protocol = "mobility";
214411677aeSAaron LI mh = (const struct ip6_mobility *)bp;
21541c99275SPeter Avalos
21641c99275SPeter Avalos /* 'ep' points to the end of available data. */
217411677aeSAaron LI ep = ndo->ndo_snapend;
21841c99275SPeter Avalos
219*ed775ee7SAntonio Huete Jimenez if (!ND_TTEST_1(mh->ip6m_len)) {
22041c99275SPeter Avalos /*
22141c99275SPeter Avalos * There's not enough captured data to include the
22241c99275SPeter Avalos * mobility header length.
22341c99275SPeter Avalos *
22441c99275SPeter Avalos * Our caller expects us to return the length, however,
22541c99275SPeter Avalos * so return a value that will run to the end of the
22641c99275SPeter Avalos * captured data.
22741c99275SPeter Avalos *
22841c99275SPeter Avalos * XXX - "ip6_print()" doesn't do anything with the
22941c99275SPeter Avalos * returned length, however, as it breaks out of the
23041c99275SPeter Avalos * header-processing loop.
23141c99275SPeter Avalos */
232*ed775ee7SAntonio Huete Jimenez mhlen = (unsigned)(ep - bp);
23341c99275SPeter Avalos goto trunc;
23441c99275SPeter Avalos }
235*ed775ee7SAntonio Huete Jimenez mhlen = (GET_U_1(mh->ip6m_len) + 1) << 3;
23641c99275SPeter Avalos
23741c99275SPeter Avalos /* XXX ip6m_cksum */
23841c99275SPeter Avalos
239*ed775ee7SAntonio Huete Jimenez type = GET_U_1(mh->ip6m_type);
240411677aeSAaron LI if (type <= IP6M_MAX && mhlen < ip6m_hdrlen[type]) {
241*ed775ee7SAntonio Huete Jimenez ND_PRINT("(header length %u is too small for type %u)", mhlen, type);
242411677aeSAaron LI goto trunc;
243411677aeSAaron LI }
244*ed775ee7SAntonio Huete Jimenez ND_PRINT("mobility: %s", tok2str(ip6m_str, "type-#%u", type));
24541c99275SPeter Avalos switch (type) {
24641c99275SPeter Avalos case IP6M_BINDING_REQUEST:
24741c99275SPeter Avalos hlen = IP6M_MINLEN;
24841c99275SPeter Avalos break;
24941c99275SPeter Avalos case IP6M_HOME_TEST_INIT:
25041c99275SPeter Avalos case IP6M_CAREOF_TEST_INIT:
25141c99275SPeter Avalos hlen = IP6M_MINLEN;
252411677aeSAaron LI if (ndo->ndo_vflag) {
253*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %s Init Cookie=%08x:%08x",
25441c99275SPeter Avalos type == IP6M_HOME_TEST_INIT ? "Home" : "Care-of",
255*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(bp + hlen),
256*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(bp + hlen + 4));
25741c99275SPeter Avalos }
25841c99275SPeter Avalos hlen += 8;
25941c99275SPeter Avalos break;
26041c99275SPeter Avalos case IP6M_HOME_TEST:
26141c99275SPeter Avalos case IP6M_CAREOF_TEST:
262*ed775ee7SAntonio Huete Jimenez ND_PRINT(" nonce id=0x%x", GET_BE_U_2(mh->ip6m_data16[0]));
26341c99275SPeter Avalos hlen = IP6M_MINLEN;
264411677aeSAaron LI if (ndo->ndo_vflag) {
265*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %s Init Cookie=%08x:%08x",
26641c99275SPeter Avalos type == IP6M_HOME_TEST ? "Home" : "Care-of",
267*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(bp + hlen),
268*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(bp + hlen + 4));
26941c99275SPeter Avalos }
27041c99275SPeter Avalos hlen += 8;
271411677aeSAaron LI if (ndo->ndo_vflag) {
272*ed775ee7SAntonio Huete Jimenez ND_PRINT(" %s Keygen Token=%08x:%08x",
27341c99275SPeter Avalos type == IP6M_HOME_TEST ? "Home" : "Care-of",
274*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(bp + hlen),
275*ed775ee7SAntonio Huete Jimenez GET_BE_U_4(bp + hlen + 4));
27641c99275SPeter Avalos }
27741c99275SPeter Avalos hlen += 8;
27841c99275SPeter Avalos break;
27941c99275SPeter Avalos case IP6M_BINDING_UPDATE:
280*ed775ee7SAntonio Huete Jimenez {
281*ed775ee7SAntonio Huete Jimenez int bits;
282*ed775ee7SAntonio Huete Jimenez ND_PRINT(" seq#=%u", GET_BE_U_2(mh->ip6m_data16[0]));
28341c99275SPeter Avalos hlen = IP6M_MINLEN;
284*ed775ee7SAntonio Huete Jimenez ND_TCHECK_2(bp + hlen);
285*ed775ee7SAntonio Huete Jimenez bits = (GET_U_1(bp + hlen) & 0xf0) >> 4;
286*ed775ee7SAntonio Huete Jimenez if (bits) {
287*ed775ee7SAntonio Huete Jimenez ND_PRINT(" ");
288*ed775ee7SAntonio Huete Jimenez ND_PRINT("%s",
289*ed775ee7SAntonio Huete Jimenez bittok2str_nosep(ip6m_binding_update_bits,
290*ed775ee7SAntonio Huete Jimenez "bits-#0x%x", bits));
291411677aeSAaron LI }
29241c99275SPeter Avalos /* Reserved (4bits) */
29341c99275SPeter Avalos hlen += 1;
29441c99275SPeter Avalos /* Reserved (8bits) */
29541c99275SPeter Avalos hlen += 1;
29641c99275SPeter Avalos /* units of 4 secs */
297*ed775ee7SAntonio Huete Jimenez ND_PRINT(" lifetime=%u", GET_BE_U_2(bp + hlen) << 2);
29841c99275SPeter Avalos hlen += 2;
29941c99275SPeter Avalos break;
300*ed775ee7SAntonio Huete Jimenez }
30141c99275SPeter Avalos case IP6M_BINDING_ACK:
302*ed775ee7SAntonio Huete Jimenez ND_PRINT(" status=%u", GET_U_1(mh->ip6m_data8[0]));
303*ed775ee7SAntonio Huete Jimenez if (GET_U_1(mh->ip6m_data8[1]) & 0x80)
304*ed775ee7SAntonio Huete Jimenez ND_PRINT(" K");
30541c99275SPeter Avalos /* Reserved (7bits) */
30641c99275SPeter Avalos hlen = IP6M_MINLEN;
307*ed775ee7SAntonio Huete Jimenez ND_PRINT(" seq#=%u", GET_BE_U_2(bp + hlen));
30841c99275SPeter Avalos hlen += 2;
30941c99275SPeter Avalos /* units of 4 secs */
310*ed775ee7SAntonio Huete Jimenez ND_PRINT(" lifetime=%u", GET_BE_U_2(bp + hlen) << 2);
31141c99275SPeter Avalos hlen += 2;
31241c99275SPeter Avalos break;
31341c99275SPeter Avalos case IP6M_BINDING_ERROR:
314*ed775ee7SAntonio Huete Jimenez ND_PRINT(" status=%u", GET_U_1(mh->ip6m_data8[0]));
31541c99275SPeter Avalos /* Reserved */
31641c99275SPeter Avalos hlen = IP6M_MINLEN;
317*ed775ee7SAntonio Huete Jimenez ND_PRINT(" homeaddr %s", GET_IP6ADDR_STRING(bp + hlen));
31841c99275SPeter Avalos hlen += 16;
31941c99275SPeter Avalos break;
32041c99275SPeter Avalos default:
321*ed775ee7SAntonio Huete Jimenez ND_PRINT(" len=%u", GET_U_1(mh->ip6m_len));
32241c99275SPeter Avalos return(mhlen);
32341c99275SPeter Avalos break;
32441c99275SPeter Avalos }
325411677aeSAaron LI if (ndo->ndo_vflag)
326*ed775ee7SAntonio Huete Jimenez if (mobility_opt_print(ndo, bp + hlen, mhlen - hlen))
327*ed775ee7SAntonio Huete Jimenez goto trunc;
32841c99275SPeter Avalos
32941c99275SPeter Avalos return(mhlen);
33041c99275SPeter Avalos
33141c99275SPeter Avalos trunc:
332*ed775ee7SAntonio Huete Jimenez nd_print_trunc(ndo);
333411677aeSAaron LI return(-1);
33441c99275SPeter Avalos }
335