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