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