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