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