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