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 73 /* XXX: unused */ 74 #define IP6MOPT_BU_MINLEN 10 75 #define IP6MOPT_BA_MINLEN 13 76 #define IP6MOPT_BR_MINLEN 2 77 78 /* Mobility Header Options */ 79 #define IP6MOPT_MINLEN 2 80 #define IP6MOPT_PAD1 0x0 /* Pad1 */ 81 #define IP6MOPT_PADN 0x1 /* PadN */ 82 #define IP6MOPT_REFRESH 0x2 /* Binding Refresh Advice */ 83 #define IP6MOPT_REFRESH_MINLEN 4 84 #define IP6MOPT_ALTCOA 0x3 /* Alternate Care-of Address */ 85 #define IP6MOPT_ALTCOA_MINLEN 18 86 #define IP6MOPT_NONCEID 0x4 /* Nonce Indices */ 87 #define IP6MOPT_NONCEID_MINLEN 6 88 #define IP6MOPT_AUTH 0x5 /* Binding Authorization Data */ 89 #define IP6MOPT_AUTH_MINLEN 12 90 91 static void 92 mobility_opt_print(netdissect_options *ndo, 93 const u_char *bp, const unsigned len) 94 { 95 unsigned i, optlen; 96 97 for (i = 0; i < len; i += optlen) { 98 if (bp[i] == IP6MOPT_PAD1) 99 optlen = 1; 100 else { 101 if (i + 1 < len) 102 optlen = bp[i + 1] + 2; 103 else 104 goto trunc; 105 } 106 if (i + optlen > len) 107 goto trunc; 108 109 switch (bp[i]) { 110 case IP6MOPT_PAD1: 111 ND_PRINT((ndo, "(pad1)")); 112 break; 113 case IP6MOPT_PADN: 114 if (len - i < IP6MOPT_MINLEN) { 115 ND_PRINT((ndo, "(padn: trunc)")); 116 goto trunc; 117 } 118 ND_PRINT((ndo, "(padn)")); 119 break; 120 case IP6MOPT_REFRESH: 121 if (len - i < IP6MOPT_REFRESH_MINLEN) { 122 ND_PRINT((ndo, "(refresh: trunc)")); 123 goto trunc; 124 } 125 /* units of 4 secs */ 126 ND_PRINT((ndo, "(refresh: %u)", 127 EXTRACT_16BITS(&bp[i+2]) << 2)); 128 break; 129 case IP6MOPT_ALTCOA: 130 if (len - i < IP6MOPT_ALTCOA_MINLEN) { 131 ND_PRINT((ndo, "(altcoa: trunc)")); 132 goto trunc; 133 } 134 ND_PRINT((ndo, "(alt-CoA: %s)", ip6addr_string(ndo, &bp[i+2]))); 135 break; 136 case IP6MOPT_NONCEID: 137 if (len - i < IP6MOPT_NONCEID_MINLEN) { 138 ND_PRINT((ndo, "(ni: trunc)")); 139 goto trunc; 140 } 141 ND_PRINT((ndo, "(ni: ho=0x%04x co=0x%04x)", 142 EXTRACT_16BITS(&bp[i+2]), 143 EXTRACT_16BITS(&bp[i+4]))); 144 break; 145 case IP6MOPT_AUTH: 146 if (len - i < IP6MOPT_AUTH_MINLEN) { 147 ND_PRINT((ndo, "(auth: trunc)")); 148 goto trunc; 149 } 150 ND_PRINT((ndo, "(auth)")); 151 break; 152 default: 153 if (len - i < IP6MOPT_MINLEN) { 154 ND_PRINT((ndo, "(sopt_type %u: trunc)", bp[i])); 155 goto trunc; 156 } 157 ND_PRINT((ndo, "(type-0x%02x: len=%u)", bp[i], bp[i + 1])); 158 break; 159 } 160 } 161 return; 162 163 trunc: 164 ND_PRINT((ndo, "[trunc] ")); 165 } 166 167 /* 168 * Mobility Header 169 */ 170 int 171 mobility_print(netdissect_options *ndo, 172 const u_char *bp, const u_char *bp2 _U_) 173 { 174 const struct ip6_mobility *mh; 175 const u_char *ep; 176 unsigned mhlen, hlen; 177 uint8_t type; 178 179 mh = (struct ip6_mobility *)bp; 180 181 /* 'ep' points to the end of available data. */ 182 ep = ndo->ndo_snapend; 183 184 if (!ND_TTEST(mh->ip6m_len)) { 185 /* 186 * There's not enough captured data to include the 187 * mobility header length. 188 * 189 * Our caller expects us to return the length, however, 190 * so return a value that will run to the end of the 191 * captured data. 192 * 193 * XXX - "ip6_print()" doesn't do anything with the 194 * returned length, however, as it breaks out of the 195 * header-processing loop. 196 */ 197 mhlen = ep - bp; 198 goto trunc; 199 } 200 mhlen = (mh->ip6m_len + 1) << 3; 201 202 /* XXX ip6m_cksum */ 203 204 ND_TCHECK(mh->ip6m_type); 205 type = mh->ip6m_type; 206 switch (type) { 207 case IP6M_BINDING_REQUEST: 208 ND_PRINT((ndo, "mobility: BRR")); 209 hlen = IP6M_MINLEN; 210 break; 211 case IP6M_HOME_TEST_INIT: 212 case IP6M_CAREOF_TEST_INIT: 213 ND_PRINT((ndo, "mobility: %soTI", 214 type == IP6M_HOME_TEST_INIT ? "H" : "C")); 215 hlen = IP6M_MINLEN; 216 if (ndo->ndo_vflag) { 217 ND_TCHECK2(*mh, hlen + 8); 218 ND_PRINT((ndo, " %s Init Cookie=%08x:%08x", 219 type == IP6M_HOME_TEST_INIT ? "Home" : "Care-of", 220 EXTRACT_32BITS(&bp[hlen]), 221 EXTRACT_32BITS(&bp[hlen + 4]))); 222 } 223 hlen += 8; 224 break; 225 case IP6M_HOME_TEST: 226 case IP6M_CAREOF_TEST: 227 ND_PRINT((ndo, "mobility: %soT", 228 type == IP6M_HOME_TEST ? "H" : "C")); 229 ND_TCHECK(mh->ip6m_data16[0]); 230 ND_PRINT((ndo, " nonce id=0x%x", EXTRACT_16BITS(&mh->ip6m_data16[0]))); 231 hlen = IP6M_MINLEN; 232 if (ndo->ndo_vflag) { 233 ND_TCHECK2(*mh, hlen + 8); 234 ND_PRINT((ndo, " %s Init Cookie=%08x:%08x", 235 type == IP6M_HOME_TEST ? "Home" : "Care-of", 236 EXTRACT_32BITS(&bp[hlen]), 237 EXTRACT_32BITS(&bp[hlen + 4]))); 238 } 239 hlen += 8; 240 if (ndo->ndo_vflag) { 241 ND_TCHECK2(*mh, hlen + 8); 242 ND_PRINT((ndo, " %s Keygen Token=%08x:%08x", 243 type == IP6M_HOME_TEST ? "Home" : "Care-of", 244 EXTRACT_32BITS(&bp[hlen]), 245 EXTRACT_32BITS(&bp[hlen + 4]))); 246 } 247 hlen += 8; 248 break; 249 case IP6M_BINDING_UPDATE: 250 ND_PRINT((ndo, "mobility: BU")); 251 ND_TCHECK(mh->ip6m_data16[0]); 252 ND_PRINT((ndo, " seq#=%u", EXTRACT_16BITS(&mh->ip6m_data16[0]))); 253 hlen = IP6M_MINLEN; 254 ND_TCHECK2(*mh, hlen + 1); 255 if (bp[hlen] & 0xf0) 256 ND_PRINT((ndo, " ")); 257 if (bp[hlen] & 0x80) 258 ND_PRINT((ndo, "A")); 259 if (bp[hlen] & 0x40) 260 ND_PRINT((ndo, "H")); 261 if (bp[hlen] & 0x20) 262 ND_PRINT((ndo, "L")); 263 if (bp[hlen] & 0x10) 264 ND_PRINT((ndo, "K")); 265 /* Reserved (4bits) */ 266 hlen += 1; 267 /* Reserved (8bits) */ 268 hlen += 1; 269 ND_TCHECK2(*mh, hlen + 2); 270 /* units of 4 secs */ 271 ND_PRINT((ndo, " lifetime=%u", EXTRACT_16BITS(&bp[hlen]) << 2)); 272 hlen += 2; 273 break; 274 case IP6M_BINDING_ACK: 275 ND_PRINT((ndo, "mobility: BA")); 276 ND_TCHECK(mh->ip6m_data8[0]); 277 ND_PRINT((ndo, " status=%u", mh->ip6m_data8[0])); 278 if (mh->ip6m_data8[1] & 0x80) 279 ND_PRINT((ndo, " K")); 280 /* Reserved (7bits) */ 281 hlen = IP6M_MINLEN; 282 ND_TCHECK2(*mh, hlen + 2); 283 ND_PRINT((ndo, " seq#=%u", EXTRACT_16BITS(&bp[hlen]))); 284 hlen += 2; 285 ND_TCHECK2(*mh, hlen + 2); 286 /* units of 4 secs */ 287 ND_PRINT((ndo, " lifetime=%u", EXTRACT_16BITS(&bp[hlen]) << 2)); 288 hlen += 2; 289 break; 290 case IP6M_BINDING_ERROR: 291 ND_PRINT((ndo, "mobility: BE")); 292 ND_TCHECK(mh->ip6m_data8[0]); 293 ND_PRINT((ndo, " status=%u", mh->ip6m_data8[0])); 294 /* Reserved */ 295 hlen = IP6M_MINLEN; 296 ND_TCHECK2(*mh, hlen + 16); 297 ND_PRINT((ndo, " homeaddr %s", ip6addr_string(ndo, &bp[hlen]))); 298 hlen += 16; 299 break; 300 default: 301 ND_PRINT((ndo, "mobility: type-#%u len=%u", type, mh->ip6m_len)); 302 return(mhlen); 303 break; 304 } 305 if (ndo->ndo_vflag) 306 mobility_opt_print(ndo, &bp[hlen], mhlen - hlen); 307 308 return(mhlen); 309 310 trunc: 311 ND_PRINT((ndo, "[|MOBILITY]")); 312 return(mhlen); 313 } 314 #endif /* INET6 */ 315