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