print-mobility.c revision 1.8
1/*
2 * Copyright (C) 2002 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#include <sys/cdefs.h>
31#ifndef lint
32__RCSID("$NetBSD: print-mobility.c,v 1.8 2017/09/08 14:01:13 christos Exp $");
33#endif
34
35/* \summary: IPv6 mobility printer */
36/* RFC 3775 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42#include <netdissect-stdinc.h>
43
44#include "netdissect.h"
45#include "addrtoname.h"
46#include "extract.h"
47
48#include "ip6.h"
49
50static const char tstr[] = "[|MOBILITY]";
51
52/* Mobility header */
53struct ip6_mobility {
54	uint8_t ip6m_pproto;	/* following payload protocol (for PG) */
55	uint8_t ip6m_len;	/* length in units of 8 octets */
56	uint8_t ip6m_type;	/* message type */
57	uint8_t reserved;	/* reserved */
58	uint16_t ip6m_cksum;	/* sum of IPv6 pseudo-header and MH */
59	union {
60		uint16_t	ip6m_un_data16[1]; /* type-specific field */
61		uint8_t		ip6m_un_data8[2];  /* type-specific field */
62	} ip6m_dataun;
63};
64
65#define ip6m_data16	ip6m_dataun.ip6m_un_data16
66#define ip6m_data8	ip6m_dataun.ip6m_un_data8
67
68#define IP6M_MINLEN	8
69
70/* http://www.iana.org/assignments/mobility-parameters/mobility-parameters.xhtml */
71
72/* message type */
73#define IP6M_BINDING_REQUEST	0	/* Binding Refresh Request */
74#define IP6M_HOME_TEST_INIT	1	/* Home Test Init */
75#define IP6M_CAREOF_TEST_INIT	2	/* Care-of Test Init */
76#define IP6M_HOME_TEST		3	/* Home Test */
77#define IP6M_CAREOF_TEST	4	/* Care-of Test */
78#define IP6M_BINDING_UPDATE	5	/* Binding Update */
79#define IP6M_BINDING_ACK	6	/* Binding Acknowledgement */
80#define IP6M_BINDING_ERROR	7	/* Binding Error */
81#define IP6M_MAX		7
82
83static const struct tok ip6m_str[] = {
84	{ IP6M_BINDING_REQUEST,  "BRR"  },
85	{ IP6M_HOME_TEST_INIT,   "HoTI" },
86	{ IP6M_CAREOF_TEST_INIT, "CoTI" },
87	{ IP6M_HOME_TEST,        "HoT"  },
88	{ IP6M_CAREOF_TEST,      "CoT"  },
89	{ IP6M_BINDING_UPDATE,   "BU"   },
90	{ IP6M_BINDING_ACK,      "BA"   },
91	{ IP6M_BINDING_ERROR,    "BE"   },
92	{ 0, NULL }
93};
94
95static const unsigned ip6m_hdrlen[IP6M_MAX + 1] = {
96	IP6M_MINLEN,      /* IP6M_BINDING_REQUEST  */
97	IP6M_MINLEN + 8,  /* IP6M_HOME_TEST_INIT   */
98	IP6M_MINLEN + 8,  /* IP6M_CAREOF_TEST_INIT */
99	IP6M_MINLEN + 16, /* IP6M_HOME_TEST        */
100	IP6M_MINLEN + 16, /* IP6M_CAREOF_TEST      */
101	IP6M_MINLEN + 4,  /* IP6M_BINDING_UPDATE   */
102	IP6M_MINLEN + 4,  /* IP6M_BINDING_ACK      */
103	IP6M_MINLEN + 16, /* IP6M_BINDING_ERROR    */
104};
105
106/* Mobility Header Options */
107#define IP6MOPT_MINLEN		2
108#define IP6MOPT_PAD1          0x0	/* Pad1 */
109#define IP6MOPT_PADN          0x1	/* PadN */
110#define IP6MOPT_REFRESH	      0x2	/* Binding Refresh Advice */
111#define IP6MOPT_REFRESH_MINLEN  4
112#define IP6MOPT_ALTCOA        0x3	/* Alternate Care-of Address */
113#define IP6MOPT_ALTCOA_MINLEN  18
114#define IP6MOPT_NONCEID       0x4	/* Nonce Indices */
115#define IP6MOPT_NONCEID_MINLEN  6
116#define IP6MOPT_AUTH          0x5	/* Binding Authorization Data */
117#define IP6MOPT_AUTH_MINLEN    12
118
119static int
120mobility_opt_print(netdissect_options *ndo,
121                   const u_char *bp, const unsigned len)
122{
123	unsigned i, optlen;
124
125	for (i = 0; i < len; i += optlen) {
126		ND_TCHECK(bp[i]);
127		if (bp[i] == IP6MOPT_PAD1)
128			optlen = 1;
129		else {
130			if (i + 1 < len) {
131				ND_TCHECK(bp[i + 1]);
132				optlen = bp[i + 1] + 2;
133			}
134			else
135				goto trunc;
136		}
137		if (i + optlen > len)
138			goto trunc;
139		ND_TCHECK(bp[i + optlen]);
140
141		switch (bp[i]) {
142		case IP6MOPT_PAD1:
143			ND_PRINT((ndo, "(pad1)"));
144			break;
145		case IP6MOPT_PADN:
146			if (len - i < IP6MOPT_MINLEN) {
147				ND_PRINT((ndo, "(padn: trunc)"));
148				goto trunc;
149			}
150			ND_PRINT((ndo, "(padn)"));
151			break;
152		case IP6MOPT_REFRESH:
153			if (len - i < IP6MOPT_REFRESH_MINLEN) {
154				ND_PRINT((ndo, "(refresh: trunc)"));
155				goto trunc;
156			}
157			/* units of 4 secs */
158			ND_TCHECK_16BITS(&bp[i+2]);
159			ND_PRINT((ndo, "(refresh: %u)",
160				EXTRACT_16BITS(&bp[i+2]) << 2));
161			break;
162		case IP6MOPT_ALTCOA:
163			if (len - i < IP6MOPT_ALTCOA_MINLEN) {
164				ND_PRINT((ndo, "(altcoa: trunc)"));
165				goto trunc;
166			}
167			ND_TCHECK_128BITS(&bp[i+2]);
168			ND_PRINT((ndo, "(alt-CoA: %s)", ip6addr_string(ndo, &bp[i+2])));
169			break;
170		case IP6MOPT_NONCEID:
171			if (len - i < IP6MOPT_NONCEID_MINLEN) {
172				ND_PRINT((ndo, "(ni: trunc)"));
173				goto trunc;
174			}
175			ND_TCHECK_16BITS(&bp[i+2]);
176			ND_TCHECK_16BITS(&bp[i+4]);
177			ND_PRINT((ndo, "(ni: ho=0x%04x co=0x%04x)",
178				EXTRACT_16BITS(&bp[i+2]),
179				EXTRACT_16BITS(&bp[i+4])));
180			break;
181		case IP6MOPT_AUTH:
182			if (len - i < IP6MOPT_AUTH_MINLEN) {
183				ND_PRINT((ndo, "(auth: trunc)"));
184				goto trunc;
185			}
186			ND_PRINT((ndo, "(auth)"));
187			break;
188		default:
189			if (len - i < IP6MOPT_MINLEN) {
190				ND_PRINT((ndo, "(sopt_type %u: trunc)", bp[i]));
191				goto trunc;
192			}
193			ND_PRINT((ndo, "(type-0x%02x: len=%u)", bp[i], bp[i + 1]));
194			break;
195		}
196	}
197	return 0;
198
199trunc:
200	return 1;
201}
202
203/*
204 * Mobility Header
205 */
206int
207mobility_print(netdissect_options *ndo,
208               const u_char *bp, const u_char *bp2 _U_)
209{
210	const struct ip6_mobility *mh;
211	const u_char *ep;
212	unsigned mhlen, hlen;
213	uint8_t type;
214
215	mh = (const struct ip6_mobility *)bp;
216
217	/* 'ep' points to the end of available data. */
218	ep = ndo->ndo_snapend;
219
220	if (!ND_TTEST(mh->ip6m_len)) {
221		/*
222		 * There's not enough captured data to include the
223		 * mobility header length.
224		 *
225		 * Our caller expects us to return the length, however,
226		 * so return a value that will run to the end of the
227		 * captured data.
228		 *
229		 * XXX - "ip6_print()" doesn't do anything with the
230		 * returned length, however, as it breaks out of the
231		 * header-processing loop.
232		 */
233		mhlen = ep - bp;
234		goto trunc;
235	}
236	mhlen = (mh->ip6m_len + 1) << 3;
237
238	/* XXX ip6m_cksum */
239
240	ND_TCHECK(mh->ip6m_type);
241	type = mh->ip6m_type;
242	if (type <= IP6M_MAX && mhlen < ip6m_hdrlen[type]) {
243		ND_PRINT((ndo, "(header length %u is too small for type %u)", mhlen, type));
244		goto trunc;
245	}
246	ND_PRINT((ndo, "mobility: %s", tok2str(ip6m_str, "type-#%u", type)));
247	switch (type) {
248	case IP6M_BINDING_REQUEST:
249		hlen = IP6M_MINLEN;
250		break;
251	case IP6M_HOME_TEST_INIT:
252	case IP6M_CAREOF_TEST_INIT:
253		hlen = IP6M_MINLEN;
254		if (ndo->ndo_vflag) {
255			ND_TCHECK_32BITS(&bp[hlen + 4]);
256			ND_PRINT((ndo, " %s Init Cookie=%08x:%08x",
257			       type == IP6M_HOME_TEST_INIT ? "Home" : "Care-of",
258			       EXTRACT_32BITS(&bp[hlen]),
259			       EXTRACT_32BITS(&bp[hlen + 4])));
260		}
261		hlen += 8;
262		break;
263	case IP6M_HOME_TEST:
264	case IP6M_CAREOF_TEST:
265		ND_TCHECK(mh->ip6m_data16[0]);
266		ND_PRINT((ndo, " nonce id=0x%x", EXTRACT_16BITS(&mh->ip6m_data16[0])));
267		hlen = IP6M_MINLEN;
268		if (ndo->ndo_vflag) {
269			ND_TCHECK_32BITS(&bp[hlen + 4]);
270			ND_PRINT((ndo, " %s Init Cookie=%08x:%08x",
271			       type == IP6M_HOME_TEST ? "Home" : "Care-of",
272			       EXTRACT_32BITS(&bp[hlen]),
273			       EXTRACT_32BITS(&bp[hlen + 4])));
274		}
275		hlen += 8;
276		if (ndo->ndo_vflag) {
277			ND_TCHECK_32BITS(&bp[hlen + 4]);
278			ND_PRINT((ndo, " %s Keygen Token=%08x:%08x",
279			       type == IP6M_HOME_TEST ? "Home" : "Care-of",
280			       EXTRACT_32BITS(&bp[hlen]),
281			       EXTRACT_32BITS(&bp[hlen + 4])));
282		}
283		hlen += 8;
284		break;
285	case IP6M_BINDING_UPDATE:
286		ND_TCHECK(mh->ip6m_data16[0]);
287		ND_PRINT((ndo, " seq#=%u", EXTRACT_16BITS(&mh->ip6m_data16[0])));
288		hlen = IP6M_MINLEN;
289		ND_TCHECK_16BITS(&bp[hlen]);
290		if (bp[hlen] & 0xf0) {
291			ND_PRINT((ndo, " "));
292			if (bp[hlen] & 0x80)
293				ND_PRINT((ndo, "A"));
294			if (bp[hlen] & 0x40)
295				ND_PRINT((ndo, "H"));
296			if (bp[hlen] & 0x20)
297				ND_PRINT((ndo, "L"));
298			if (bp[hlen] & 0x10)
299				ND_PRINT((ndo, "K"));
300		}
301		/* Reserved (4bits) */
302		hlen += 1;
303		/* Reserved (8bits) */
304		hlen += 1;
305		ND_TCHECK_16BITS(&bp[hlen]);
306		/* units of 4 secs */
307		ND_PRINT((ndo, " lifetime=%u", EXTRACT_16BITS(&bp[hlen]) << 2));
308		hlen += 2;
309		break;
310	case IP6M_BINDING_ACK:
311		ND_TCHECK(mh->ip6m_data8[0]);
312		ND_PRINT((ndo, " status=%u", mh->ip6m_data8[0]));
313		ND_TCHECK(mh->ip6m_data8[1]);
314		if (mh->ip6m_data8[1] & 0x80)
315			ND_PRINT((ndo, " K"));
316		/* Reserved (7bits) */
317		hlen = IP6M_MINLEN;
318		ND_TCHECK_16BITS(&bp[hlen]);
319		ND_PRINT((ndo, " seq#=%u", EXTRACT_16BITS(&bp[hlen])));
320		hlen += 2;
321		ND_TCHECK_16BITS(&bp[hlen]);
322		/* units of 4 secs */
323		ND_PRINT((ndo, " lifetime=%u", EXTRACT_16BITS(&bp[hlen]) << 2));
324		hlen += 2;
325		break;
326	case IP6M_BINDING_ERROR:
327		ND_TCHECK(mh->ip6m_data8[0]);
328		ND_PRINT((ndo, " status=%u", mh->ip6m_data8[0]));
329		/* Reserved */
330		hlen = IP6M_MINLEN;
331		ND_TCHECK2(bp[hlen], 16);
332		ND_PRINT((ndo, " homeaddr %s", ip6addr_string(ndo, &bp[hlen])));
333		hlen += 16;
334		break;
335	default:
336		ND_PRINT((ndo, " len=%u", mh->ip6m_len));
337		return(mhlen);
338		break;
339	}
340	if (ndo->ndo_vflag)
341		if (mobility_opt_print(ndo, &bp[hlen], mhlen - hlen))
342			goto trunc;;
343
344	return(mhlen);
345
346 trunc:
347	ND_PRINT((ndo, "%s", tstr));
348	return(-1);
349}
350