xref: /netbsd-src/external/bsd/tcpdump/dist/print-mobility.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (C) 2002 WIDE Project.
30f74e101Schristos  * All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that the following conditions
70f74e101Schristos  * are met:
80f74e101Schristos  * 1. Redistributions of source code must retain the above copyright
90f74e101Schristos  *    notice, this list of conditions and the following disclaimer.
100f74e101Schristos  * 2. Redistributions in binary form must reproduce the above copyright
110f74e101Schristos  *    notice, this list of conditions and the following disclaimer in the
120f74e101Schristos  *    documentation and/or other materials provided with the distribution.
130f74e101Schristos  * 3. Neither the name of the project nor the names of its contributors
140f74e101Schristos  *    may be used to endorse or promote products derived from this software
150f74e101Schristos  *    without specific prior written permission.
160f74e101Schristos  *
170f74e101Schristos  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
180f74e101Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190f74e101Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200f74e101Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
210f74e101Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
220f74e101Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
230f74e101Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
240f74e101Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
250f74e101Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
260f74e101Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270f74e101Schristos  * SUCH DAMAGE.
280f74e101Schristos  */
290f74e101Schristos 
3011b3aaa1Schristos #include <sys/cdefs.h>
310f74e101Schristos #ifndef lint
32*26ba0b50Schristos __RCSID("$NetBSD: print-mobility.c,v 1.10 2024/09/02 16:15:32 christos Exp $");
3311b3aaa1Schristos #endif
34b3a00663Schristos 
35dc860a36Sspz /* \summary: IPv6 mobility printer */
3672c96ff3Schristos /* RFC 3775 */
37dc860a36Sspz 
38c74ad251Schristos #include <config.h>
390f74e101Schristos 
40c74ad251Schristos #include "netdissect-stdinc.h"
410f74e101Schristos 
42fdccd7e4Schristos #include "netdissect.h"
430f74e101Schristos #include "addrtoname.h"
44fdccd7e4Schristos #include "extract.h"
450f74e101Schristos 
4672c96ff3Schristos #include "ip6.h"
4772c96ff3Schristos 
48dc860a36Sspz 
490f74e101Schristos /* Mobility header */
500f74e101Schristos struct ip6_mobility {
51c74ad251Schristos 	nd_uint8_t ip6m_pproto;	/* following payload protocol (for PG) */
52c74ad251Schristos 	nd_uint8_t ip6m_len;	/* length in units of 8 octets */
53c74ad251Schristos 	nd_uint8_t ip6m_type;	/* message type */
54c74ad251Schristos 	nd_uint8_t reserved;	/* reserved */
55c74ad251Schristos 	nd_uint16_t ip6m_cksum;	/* sum of IPv6 pseudo-header and MH */
560f74e101Schristos 	union {
57c74ad251Schristos 		nd_uint16_t	ip6m_un_data16[1]; /* type-specific field */
58c74ad251Schristos 		nd_uint8_t	ip6m_un_data8[2];  /* type-specific field */
590f74e101Schristos 	} ip6m_dataun;
600f74e101Schristos };
610f74e101Schristos 
620f74e101Schristos #define ip6m_data16	ip6m_dataun.ip6m_un_data16
630f74e101Schristos #define ip6m_data8	ip6m_dataun.ip6m_un_data8
640f74e101Schristos 
650f74e101Schristos #define IP6M_MINLEN	8
660f74e101Schristos 
67c74ad251Schristos /* https://www.iana.org/assignments/mobility-parameters/mobility-parameters.xhtml */
68b3a00663Schristos 
690f74e101Schristos /* message type */
700f74e101Schristos #define IP6M_BINDING_REQUEST	0	/* Binding Refresh Request */
710f74e101Schristos #define IP6M_HOME_TEST_INIT	1	/* Home Test Init */
720f74e101Schristos #define IP6M_CAREOF_TEST_INIT	2	/* Care-of Test Init */
730f74e101Schristos #define IP6M_HOME_TEST		3	/* Home Test */
740f74e101Schristos #define IP6M_CAREOF_TEST	4	/* Care-of Test */
750f74e101Schristos #define IP6M_BINDING_UPDATE	5	/* Binding Update */
760f74e101Schristos #define IP6M_BINDING_ACK	6	/* Binding Acknowledgement */
770f74e101Schristos #define IP6M_BINDING_ERROR	7	/* Binding Error */
78ba2ff121Schristos #define IP6M_MAX		7
79ba2ff121Schristos 
80fdccd7e4Schristos static const struct tok ip6m_str[] = {
81fdccd7e4Schristos 	{ IP6M_BINDING_REQUEST,  "BRR"  },
82fdccd7e4Schristos 	{ IP6M_HOME_TEST_INIT,   "HoTI" },
83fdccd7e4Schristos 	{ IP6M_CAREOF_TEST_INIT, "CoTI" },
84fdccd7e4Schristos 	{ IP6M_HOME_TEST,        "HoT"  },
85fdccd7e4Schristos 	{ IP6M_CAREOF_TEST,      "CoT"  },
86fdccd7e4Schristos 	{ IP6M_BINDING_UPDATE,   "BU"   },
87fdccd7e4Schristos 	{ IP6M_BINDING_ACK,      "BA"   },
88fdccd7e4Schristos 	{ IP6M_BINDING_ERROR,    "BE"   },
89fdccd7e4Schristos 	{ 0, NULL }
90fdccd7e4Schristos };
91fdccd7e4Schristos 
92ba2ff121Schristos static const unsigned ip6m_hdrlen[IP6M_MAX + 1] = {
93ba2ff121Schristos 	IP6M_MINLEN,      /* IP6M_BINDING_REQUEST  */
94ba2ff121Schristos 	IP6M_MINLEN + 8,  /* IP6M_HOME_TEST_INIT   */
95ba2ff121Schristos 	IP6M_MINLEN + 8,  /* IP6M_CAREOF_TEST_INIT */
96ba2ff121Schristos 	IP6M_MINLEN + 16, /* IP6M_HOME_TEST        */
97ba2ff121Schristos 	IP6M_MINLEN + 16, /* IP6M_CAREOF_TEST      */
98ba2ff121Schristos 	IP6M_MINLEN + 4,  /* IP6M_BINDING_UPDATE   */
99ba2ff121Schristos 	IP6M_MINLEN + 4,  /* IP6M_BINDING_ACK      */
100ba2ff121Schristos 	IP6M_MINLEN + 16, /* IP6M_BINDING_ERROR    */
101ba2ff121Schristos };
1020f74e101Schristos 
1030f74e101Schristos /* Mobility Header Options */
1040f74e101Schristos #define IP6MOPT_MINLEN		2
1050f74e101Schristos #define IP6MOPT_PAD1          0x0	/* Pad1 */
1060f74e101Schristos #define IP6MOPT_PADN          0x1	/* PadN */
1070f74e101Schristos #define IP6MOPT_REFRESH	      0x2	/* Binding Refresh Advice */
1080f74e101Schristos #define IP6MOPT_REFRESH_MINLEN  4
1090f74e101Schristos #define IP6MOPT_ALTCOA        0x3	/* Alternate Care-of Address */
1100f74e101Schristos #define IP6MOPT_ALTCOA_MINLEN  18
1110f74e101Schristos #define IP6MOPT_NONCEID       0x4	/* Nonce Indices */
1120f74e101Schristos #define IP6MOPT_NONCEID_MINLEN  6
1130f74e101Schristos #define IP6MOPT_AUTH          0x5	/* Binding Authorization Data */
1140f74e101Schristos #define IP6MOPT_AUTH_MINLEN    12
1150f74e101Schristos 
116c74ad251Schristos static const struct tok ip6m_binding_update_bits [] = {
117c74ad251Schristos 	{ 0x08, "A" },
118c74ad251Schristos 	{ 0x04, "H" },
119c74ad251Schristos 	{ 0x02, "L" },
120c74ad251Schristos 	{ 0x01, "K" },
121c74ad251Schristos 	{ 0, NULL }
122c74ad251Schristos };
123c74ad251Schristos 
124dc860a36Sspz static int
125b3a00663Schristos mobility_opt_print(netdissect_options *ndo,
126b3a00663Schristos                    const u_char *bp, const unsigned len)
1270f74e101Schristos {
128b3a00663Schristos 	unsigned i, optlen;
1290f74e101Schristos 
1300f74e101Schristos 	for (i = 0; i < len; i += optlen) {
131c74ad251Schristos 		if (GET_U_1(bp + i) == IP6MOPT_PAD1)
1320f74e101Schristos 			optlen = 1;
1330f74e101Schristos 		else {
134ba2ff121Schristos 			if (i + 1 < len) {
135c74ad251Schristos 				optlen = GET_U_1(bp + i + 1) + 2;
136*26ba0b50Schristos 			} else
1370f74e101Schristos 				goto trunc;
1380f74e101Schristos 		}
1390f74e101Schristos 		if (i + optlen > len)
1400f74e101Schristos 			goto trunc;
141c74ad251Schristos 		ND_TCHECK_1(bp + i + optlen);
1420f74e101Schristos 
143c74ad251Schristos 		switch (GET_U_1(bp + i)) {
1440f74e101Schristos 		case IP6MOPT_PAD1:
145c74ad251Schristos 			ND_PRINT("(pad1)");
1460f74e101Schristos 			break;
1470f74e101Schristos 		case IP6MOPT_PADN:
1480f74e101Schristos 			if (len - i < IP6MOPT_MINLEN) {
149c74ad251Schristos 				ND_PRINT("(padn: trunc)");
1500f74e101Schristos 				goto trunc;
1510f74e101Schristos 			}
152c74ad251Schristos 			ND_PRINT("(padn)");
1530f74e101Schristos 			break;
1540f74e101Schristos 		case IP6MOPT_REFRESH:
1550f74e101Schristos 			if (len - i < IP6MOPT_REFRESH_MINLEN) {
156c74ad251Schristos 				ND_PRINT("(refresh: trunc)");
1570f74e101Schristos 				goto trunc;
1580f74e101Schristos 			}
1590f74e101Schristos 			/* units of 4 secs */
160c74ad251Schristos 			ND_PRINT("(refresh: %u)",
161c74ad251Schristos 				GET_BE_U_2(bp + i + 2) << 2);
1620f74e101Schristos 			break;
1630f74e101Schristos 		case IP6MOPT_ALTCOA:
1640f74e101Schristos 			if (len - i < IP6MOPT_ALTCOA_MINLEN) {
165c74ad251Schristos 				ND_PRINT("(altcoa: trunc)");
1660f74e101Schristos 				goto trunc;
1670f74e101Schristos 			}
168c74ad251Schristos 			ND_PRINT("(alt-CoA: %s)", GET_IP6ADDR_STRING(bp + i + 2));
1690f74e101Schristos 			break;
1700f74e101Schristos 		case IP6MOPT_NONCEID:
1710f74e101Schristos 			if (len - i < IP6MOPT_NONCEID_MINLEN) {
172c74ad251Schristos 				ND_PRINT("(ni: trunc)");
1730f74e101Schristos 				goto trunc;
1740f74e101Schristos 			}
175c74ad251Schristos 			ND_PRINT("(ni: ho=0x%04x co=0x%04x)",
176c74ad251Schristos 				GET_BE_U_2(bp + i + 2),
177c74ad251Schristos 				GET_BE_U_2(bp + i + 4));
1780f74e101Schristos 			break;
1790f74e101Schristos 		case IP6MOPT_AUTH:
1800f74e101Schristos 			if (len - i < IP6MOPT_AUTH_MINLEN) {
181c74ad251Schristos 				ND_PRINT("(auth: trunc)");
1820f74e101Schristos 				goto trunc;
1830f74e101Schristos 			}
184c74ad251Schristos 			ND_PRINT("(auth)");
1850f74e101Schristos 			break;
1860f74e101Schristos 		default:
1870f74e101Schristos 			if (len - i < IP6MOPT_MINLEN) {
188c74ad251Schristos 				ND_PRINT("(sopt_type %u: trunc)",
189c74ad251Schristos 					 GET_U_1(bp + i));
1900f74e101Schristos 				goto trunc;
1910f74e101Schristos 			}
192c74ad251Schristos 			ND_PRINT("(type-0x%02x: len=%u)", GET_U_1(bp + i),
193c74ad251Schristos 				 GET_U_1(bp + i + 1));
1940f74e101Schristos 			break;
1950f74e101Schristos 		}
1960f74e101Schristos 	}
197dc860a36Sspz 	return 0;
1980f74e101Schristos 
1990f74e101Schristos trunc:
200dc860a36Sspz 	return 1;
2010f74e101Schristos }
2020f74e101Schristos 
2030f74e101Schristos /*
2040f74e101Schristos  * Mobility Header
2050f74e101Schristos  */
2060f74e101Schristos int
207b3a00663Schristos mobility_print(netdissect_options *ndo,
208b3a00663Schristos                const u_char *bp, const u_char *bp2 _U_)
2090f74e101Schristos {
2100f74e101Schristos 	const struct ip6_mobility *mh;
2110f74e101Schristos 	const u_char *ep;
212b3a00663Schristos 	unsigned mhlen, hlen;
213b3a00663Schristos 	uint8_t type;
2140f74e101Schristos 
215c74ad251Schristos 	ndo->ndo_protocol = "mobility";
216fdccd7e4Schristos 	mh = (const struct ip6_mobility *)bp;
2170f74e101Schristos 
2180f74e101Schristos 	/* 'ep' points to the end of available data. */
219b3a00663Schristos 	ep = ndo->ndo_snapend;
2200f74e101Schristos 
221c74ad251Schristos 	if (!ND_TTEST_1(mh->ip6m_len)) {
2220f74e101Schristos 		/*
2230f74e101Schristos 		 * There's not enough captured data to include the
2240f74e101Schristos 		 * mobility header length.
2250f74e101Schristos 		 *
2260f74e101Schristos 		 * Our caller expects us to return the length, however,
2270f74e101Schristos 		 * so return a value that will run to the end of the
2280f74e101Schristos 		 * captured data.
2290f74e101Schristos 		 *
2300f74e101Schristos 		 * XXX - "ip6_print()" doesn't do anything with the
2310f74e101Schristos 		 * returned length, however, as it breaks out of the
2320f74e101Schristos 		 * header-processing loop.
2330f74e101Schristos 		 */
234c74ad251Schristos 		mhlen = (unsigned)(ep - bp);
2350f74e101Schristos 		goto trunc;
2360f74e101Schristos 	}
237c74ad251Schristos 	mhlen = (GET_U_1(mh->ip6m_len) + 1) << 3;
2380f74e101Schristos 
2390f74e101Schristos 	/* XXX ip6m_cksum */
2400f74e101Schristos 
241c74ad251Schristos 	type = GET_U_1(mh->ip6m_type);
242ba2ff121Schristos 	if (type <= IP6M_MAX && mhlen < ip6m_hdrlen[type]) {
243c74ad251Schristos 		ND_PRINT("(header length %u is too small for type %u)", mhlen, type);
244ba2ff121Schristos 		goto trunc;
245ba2ff121Schristos 	}
246c74ad251Schristos 	ND_PRINT("mobility: %s", tok2str(ip6m_str, "type-#%u", type));
2470f74e101Schristos 	switch (type) {
2480f74e101Schristos 	case IP6M_BINDING_REQUEST:
2490f74e101Schristos 		hlen = IP6M_MINLEN;
2500f74e101Schristos 		break;
2510f74e101Schristos 	case IP6M_HOME_TEST_INIT:
2520f74e101Schristos 	case IP6M_CAREOF_TEST_INIT:
2530f74e101Schristos 		hlen = IP6M_MINLEN;
254b3a00663Schristos 		if (ndo->ndo_vflag) {
255c74ad251Schristos 			ND_PRINT(" %s Init Cookie=%08x:%08x",
2560f74e101Schristos 			       type == IP6M_HOME_TEST_INIT ? "Home" : "Care-of",
257c74ad251Schristos 			       GET_BE_U_4(bp + hlen),
258c74ad251Schristos 			       GET_BE_U_4(bp + hlen + 4));
2590f74e101Schristos 		}
2600f74e101Schristos 		hlen += 8;
2610f74e101Schristos 		break;
2620f74e101Schristos 	case IP6M_HOME_TEST:
2630f74e101Schristos 	case IP6M_CAREOF_TEST:
264c74ad251Schristos 		ND_PRINT(" nonce id=0x%x", GET_BE_U_2(mh->ip6m_data16[0]));
2650f74e101Schristos 		hlen = IP6M_MINLEN;
266b3a00663Schristos 		if (ndo->ndo_vflag) {
267c74ad251Schristos 			ND_PRINT(" %s Init Cookie=%08x:%08x",
2680f74e101Schristos 			       type == IP6M_HOME_TEST ? "Home" : "Care-of",
269c74ad251Schristos 			       GET_BE_U_4(bp + hlen),
270c74ad251Schristos 			       GET_BE_U_4(bp + hlen + 4));
2710f74e101Schristos 		}
2720f74e101Schristos 		hlen += 8;
273b3a00663Schristos 		if (ndo->ndo_vflag) {
274c74ad251Schristos 			ND_PRINT(" %s Keygen Token=%08x:%08x",
2750f74e101Schristos 			       type == IP6M_HOME_TEST ? "Home" : "Care-of",
276c74ad251Schristos 			       GET_BE_U_4(bp + hlen),
277c74ad251Schristos 			       GET_BE_U_4(bp + hlen + 4));
2780f74e101Schristos 		}
2790f74e101Schristos 		hlen += 8;
2800f74e101Schristos 		break;
2810f74e101Schristos 	case IP6M_BINDING_UPDATE:
282c74ad251Schristos 	    {
283c74ad251Schristos 		int bits;
284c74ad251Schristos 		ND_PRINT(" seq#=%u", GET_BE_U_2(mh->ip6m_data16[0]));
2850f74e101Schristos 		hlen = IP6M_MINLEN;
286c74ad251Schristos 		ND_TCHECK_2(bp + hlen);
287c74ad251Schristos 		bits = (GET_U_1(bp + hlen) & 0xf0) >> 4;
288c74ad251Schristos 		if (bits) {
289c74ad251Schristos 			ND_PRINT(" ");
290c74ad251Schristos 			ND_PRINT("%s",
291c74ad251Schristos 				 bittok2str_nosep(ip6m_binding_update_bits,
292c74ad251Schristos 				 "bits-#0x%x", bits));
29372c96ff3Schristos 		}
2940f74e101Schristos 		/* Reserved (4bits) */
2950f74e101Schristos 		hlen += 1;
2960f74e101Schristos 		/* Reserved (8bits) */
2970f74e101Schristos 		hlen += 1;
2980f74e101Schristos 		/* units of 4 secs */
299c74ad251Schristos 		ND_PRINT(" lifetime=%u", GET_BE_U_2(bp + hlen) << 2);
3000f74e101Schristos 		hlen += 2;
3010f74e101Schristos 		break;
302c74ad251Schristos 	    }
3030f74e101Schristos 	case IP6M_BINDING_ACK:
304c74ad251Schristos 		ND_PRINT(" status=%u", GET_U_1(mh->ip6m_data8[0]));
305c74ad251Schristos 		if (GET_U_1(mh->ip6m_data8[1]) & 0x80)
306c74ad251Schristos 			ND_PRINT(" K");
3070f74e101Schristos 		/* Reserved (7bits) */
3080f74e101Schristos 		hlen = IP6M_MINLEN;
309c74ad251Schristos 		ND_PRINT(" seq#=%u", GET_BE_U_2(bp + hlen));
3100f74e101Schristos 		hlen += 2;
3110f74e101Schristos 		/* units of 4 secs */
312c74ad251Schristos 		ND_PRINT(" lifetime=%u", GET_BE_U_2(bp + hlen) << 2);
3130f74e101Schristos 		hlen += 2;
3140f74e101Schristos 		break;
3150f74e101Schristos 	case IP6M_BINDING_ERROR:
316c74ad251Schristos 		ND_PRINT(" status=%u", GET_U_1(mh->ip6m_data8[0]));
3170f74e101Schristos 		/* Reserved */
3180f74e101Schristos 		hlen = IP6M_MINLEN;
319c74ad251Schristos 		ND_PRINT(" homeaddr %s", GET_IP6ADDR_STRING(bp + hlen));
3200f74e101Schristos 		hlen += 16;
3210f74e101Schristos 		break;
3220f74e101Schristos 	default:
323c74ad251Schristos 		ND_PRINT(" len=%u", GET_U_1(mh->ip6m_len));
3240f74e101Schristos 		return(mhlen);
3250f74e101Schristos 		break;
3260f74e101Schristos 	}
327b3a00663Schristos 	if (ndo->ndo_vflag)
328c74ad251Schristos 		if (mobility_opt_print(ndo, bp + hlen, mhlen - hlen))
329c74ad251Schristos 			goto trunc;
3300f74e101Schristos 
3310f74e101Schristos 	return(mhlen);
3320f74e101Schristos 
3330f74e101Schristos  trunc:
334c74ad251Schristos 	nd_print_trunc(ndo);
33572c96ff3Schristos 	return(-1);
3360f74e101Schristos }
337