1 /* 2 * Copyright (C) 1998 and 1999 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 * RFC3315: DHCPv6 31 * supported DHCPv6 options: 32 * RFC3319, 33 * draft-ietf-dhc-dhcpv6-opt-dnsconfig-04.txt, 34 * draft-ietf-dhc-dhcpv6-opt-prefix-delegation-05.txt 35 * draft-ietf-dhc-dhcpv6-opt-timeconfig-02.txt, 36 */ 37 38 #ifndef lint 39 static const char rcsid[] _U_ = 40 "@(#) $Header: /tcpdump/master/tcpdump/print-dhcp6.c,v 1.27.2.4 2003/11/18 23:26:14 guy Exp $"; 41 #endif 42 43 #ifdef HAVE_CONFIG_H 44 #include "config.h" 45 #endif 46 47 #include <tcpdump-stdinc.h> 48 49 #include <stdio.h> 50 #include <string.h> 51 52 #include "interface.h" 53 #include "addrtoname.h" 54 #include "extract.h" 55 56 /* lease duration */ 57 #define DHCP6_DURATITION_INFINITE 0xffffffff 58 59 /* Error Values */ 60 #define DH6ERR_FAILURE 16 61 #define DH6ERR_AUTHFAIL 17 62 #define DH6ERR_POORLYFORMED 18 63 #define DH6ERR_UNAVAIL 19 64 #define DH6ERR_OPTUNAVAIL 20 65 66 /* Message type */ 67 #define DH6_SOLICIT 1 68 #define DH6_ADVERTISE 2 69 #define DH6_REQUEST 3 70 #define DH6_CONFIRM 4 71 #define DH6_RENEW 5 72 #define DH6_REBIND 6 73 #define DH6_REPLY 7 74 #define DH6_RELEASE 8 75 #define DH6_DECLINE 9 76 #define DH6_RECONFIGURE 10 77 #define DH6_INFORM_REQ 11 78 #define DH6_RELAY_FORW 12 79 #define DH6_RELAY_REPLY 13 80 81 /* DHCP6 base packet format */ 82 struct dhcp6 { 83 union { 84 u_int8_t m; 85 u_int32_t x; 86 } dh6_msgtypexid; 87 /* options follow */ 88 }; 89 #define dh6_msgtype dh6_msgtypexid.m 90 #define dh6_xid dh6_msgtypexid.x 91 #define DH6_XIDMASK 0x00ffffff 92 93 /* DHCPv6 relay messages */ 94 struct dhcp6_relay { 95 u_int8_t dh6relay_msgtype; 96 u_int8_t dh6relay_hcnt; 97 u_int8_t dh6relay_linkaddr[16]; /* XXX: badly aligned */ 98 u_int8_t dh6relay_peeraddr[16]; 99 /* options follow */ 100 }; 101 102 /* options */ 103 #define DH6OPT_CLIENTID 1 104 #define DH6OPT_SERVERID 2 105 #define DH6OPT_IA_NA 3 106 #define DH6OPT_IA_TMP 4 107 #define DH6OPT_IADDR 5 108 #define DH6OPT_ORO 6 109 #define DH6OPT_PREFERENCE 7 110 # define DH6OPT_PREF_UNDEF -1 111 # define DH6OPT_PREF_MAX 255 112 #define DH6OPT_ELAPSED_TIME 8 113 #define DH6OPT_RELAY_MSG 9 114 /*#define DH6OPT_SERVER_MSG 10 deprecated */ 115 #define DH6OPT_AUTH 11 116 #define DH6OPT_UNICAST 12 117 #define DH6OPT_STATUS_CODE 13 118 # define DH6OPT_STCODE_SUCCESS 0 119 # define DH6OPT_STCODE_UNSPECFAIL 1 120 # define DH6OPT_STCODE_NOADDRAVAIL 2 121 # define DH6OPT_STCODE_NOBINDING 3 122 # define DH6OPT_STCODE_NOTONLINK 4 123 # define DH6OPT_STCODE_USEMULTICAST 5 124 # define DH6OPT_STCODE_NOPREFIXAVAIL 6 125 #define DH6OPT_RAPID_COMMIT 14 126 #define DH6OPT_USER_CLASS 15 127 #define DH6OPT_VENDOR_CLASS 16 128 #define DH6OPT_VENDOR_OPTS 17 129 #define DH6OPT_INTERFACE_ID 18 130 #define DH6OPT_RECONF_MSG 19 131 #define DH6OPT_RECONF_ACCEPT 20 132 #define DH6OPT_SIP_SERVER_D 21 133 #define DH6OPT_SIP_SERVER_A 22 134 #define DH6OPT_DNS 23 135 #define DH6OPT_DNSNAME 24 136 137 /* 138 * The option type has not been assigned for the following options. 139 * We temporarily adopt values used in the service specification document 140 * (200206xx version) by NTT Communications. 141 * Note that we'll change the following definitions if different type values 142 * are officially assigned. 143 */ 144 #define DH6OPT_PREFIX_DELEGATION 30 145 #define DH6OPT_PREFIX_INFORMATION 31 146 #define DH6OPT_PREFIX_REQUEST 32 147 148 /* 149 * The followings are also unassigned numbers. 150 * We temporarily use values as of KAME snap 20031013. 151 */ 152 #define DH6OPT_IA_PD 33 153 #define DH6OPT_IA_PD_PREFIX 34 154 #define DH6OPT_NTP_SERVERS 35 155 156 struct dhcp6opt { 157 u_int16_t dh6opt_type; 158 u_int16_t dh6opt_len; 159 /* type-dependent data follows */ 160 }; 161 162 struct dhcp6_ia { 163 u_int16_t dh6opt_ia_type; 164 u_int16_t dh6opt_ia_len; 165 u_int32_t dh6opt_ia_iaid; 166 u_int32_t dh6opt_ia_t1; 167 u_int32_t dh6opt_ia_t2; 168 }; 169 170 struct dhcp6_ia_prefix { 171 u_int16_t dh6opt_ia_prefix_type; 172 u_int16_t dh6opt_ia_prefix_len; 173 u_int32_t dh6opt_ia_prefix_pltime; 174 u_int32_t dh6opt_ia_prefix_vltime; 175 u_int8_t dh6opt_ia_prefix_plen; 176 struct in6_addr dh6opt_ia_prefix_addr; 177 } __attribute__ ((__packed__)); 178 179 static const char * 180 dhcp6opt_name(int type) 181 { 182 static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */ 183 184 if (type > 65535) 185 return "INVALID option"; 186 187 switch(type) { 188 case DH6OPT_CLIENTID: 189 return "client ID"; 190 case DH6OPT_SERVERID: 191 return "server ID"; 192 case DH6OPT_IA_NA: 193 return "IA_NA"; 194 case DH6OPT_ORO: 195 return "option request"; 196 case DH6OPT_PREFERENCE: 197 return "preference"; 198 case DH6OPT_ELAPSED_TIME: 199 return "elapsed time"; 200 case DH6OPT_RELAY_MSG: 201 return "relay message"; 202 case DH6OPT_STATUS_CODE: 203 return "status code"; 204 case DH6OPT_RAPID_COMMIT: 205 return "rapid commit"; 206 case DH6OPT_INTERFACE_ID: 207 return "interface ID"; 208 case DH6OPT_RECONF_MSG: 209 return "reconfigure message"; 210 case DH6OPT_RECONF_ACCEPT: 211 return "reconfigure accept"; 212 case DH6OPT_SIP_SERVER_D: 213 return "SIP Servers Domain"; 214 case DH6OPT_SIP_SERVER_A: 215 return "SIP Servers Address"; 216 case DH6OPT_DNS: 217 return "DNS"; 218 case DH6OPT_PREFIX_DELEGATION: 219 return "prefix delegation"; 220 case DH6OPT_PREFIX_INFORMATION: 221 return "prefix information"; 222 case DH6OPT_IA_PD: 223 return "IA_PD"; 224 case DH6OPT_IA_PD_PREFIX: 225 return "IA_PD prefix"; 226 case DH6OPT_NTP_SERVERS: 227 return "NTP Server"; 228 default: 229 snprintf(genstr, sizeof(genstr), "opt_%d", type); 230 return(genstr); 231 } 232 } 233 234 static const char * 235 dhcp6stcode(int code) 236 { 237 static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */ 238 239 if (code > 255) 240 return "INVALID code"; 241 242 switch(code) { 243 case DH6OPT_STCODE_SUCCESS: 244 return "success"; 245 case DH6OPT_STCODE_UNSPECFAIL: 246 return "unspec failure"; 247 case DH6OPT_STCODE_NOADDRAVAIL: 248 return "no addresses"; 249 case DH6OPT_STCODE_NOBINDING: 250 return "no binding"; 251 case DH6OPT_STCODE_NOTONLINK: 252 return "not on-link"; 253 case DH6OPT_STCODE_USEMULTICAST: 254 return "use multicast"; 255 case DH6OPT_STCODE_NOPREFIXAVAIL: 256 return "no prefixes"; 257 default: 258 snprintf(genstr, sizeof(genstr), "code%d", code); 259 return(genstr); 260 } 261 } 262 263 static void 264 dhcp6opt_print(const u_char *cp, const u_char *ep) 265 { 266 struct dhcp6opt *dh6o; 267 u_char *tp; 268 size_t i; 269 u_int16_t opttype; 270 size_t optlen; 271 u_int16_t val16; 272 u_int32_t val32; 273 struct in6_addr addr6; 274 struct dhcp6_ia ia; 275 struct dhcp6_ia_prefix ia_prefix; 276 277 if (cp == ep) 278 return; 279 while (cp < ep) { 280 if (ep < cp + sizeof(*dh6o)) 281 goto trunc; 282 dh6o = (struct dhcp6opt *)cp; 283 optlen = EXTRACT_16BITS(&dh6o->dh6opt_len); 284 if (ep < cp + sizeof(*dh6o) + optlen) 285 goto trunc; 286 opttype = EXTRACT_16BITS(&dh6o->dh6opt_type); 287 printf(" (%s", dhcp6opt_name(opttype)); 288 switch (opttype) { 289 case DH6OPT_CLIENTID: 290 case DH6OPT_SERVERID: 291 if (optlen < 2) { 292 /*(*/ 293 printf(" ?)"); 294 break; 295 } 296 tp = (u_char *)(dh6o + 1); 297 switch (EXTRACT_16BITS(tp)) { 298 case 1: 299 if (optlen >= 2 + 6) { 300 printf(" hwaddr/time type %u time %u ", 301 EXTRACT_16BITS(&tp[2]), 302 EXTRACT_32BITS(&tp[4])); 303 for (i = 8; i < optlen; i++) 304 printf("%02x", tp[i]); 305 /*(*/ 306 printf(")"); 307 } else { 308 /*(*/ 309 printf(" ?)"); 310 } 311 break; 312 case 2: 313 if (optlen >= 2 + 8) { 314 printf(" vid "); 315 for (i = 2; i < 2 + 8; i++) 316 printf("%02x", tp[i]); 317 /*(*/ 318 printf(")"); 319 } else { 320 /*(*/ 321 printf(" ?)"); 322 } 323 break; 324 case 3: 325 if (optlen >= 2 + 2) { 326 printf(" hwaddr type %u ", 327 EXTRACT_16BITS(&tp[2])); 328 for (i = 4; i < optlen; i++) 329 printf("%02x", tp[i]); 330 /*(*/ 331 printf(")"); 332 } else { 333 /*(*/ 334 printf(" ?)"); 335 } 336 break; 337 default: 338 printf(" type %d)", EXTRACT_16BITS(tp)); 339 break; 340 } 341 break; 342 case DH6OPT_ORO: 343 if (optlen % 2) { 344 printf(" ?)"); 345 break; 346 } 347 tp = (u_char *)(dh6o + 1); 348 for (i = 0; i < optlen; i += 2) { 349 u_int16_t opt; 350 351 memcpy(&opt, &tp[i], sizeof(opt)); 352 printf(" %s", dhcp6opt_name(ntohs(opt))); 353 } 354 printf(")"); 355 break; 356 case DH6OPT_PREFERENCE: 357 if (optlen != 1) { 358 printf(" ?)"); 359 break; 360 } 361 printf(" %d)", *((u_char *)(dh6o + 1) + 1)); 362 break; 363 case DH6OPT_ELAPSED_TIME: 364 if (optlen != 2) { 365 printf(" ?)"); 366 break; 367 } 368 memcpy(&val16, dh6o + 1, sizeof(val16)); 369 val16 = ntohs(val16); 370 printf(" %d)", (int)val16); 371 break; 372 case DH6OPT_RELAY_MSG: 373 printf(" ("); 374 dhcp6_print((const u_char *)(dh6o + 1), optlen); 375 printf(")"); 376 break; 377 case DH6OPT_RAPID_COMMIT: /* nothing todo */ 378 printf(")"); 379 break; 380 case DH6OPT_INTERFACE_ID: 381 /* 382 * Since we cannot predict the encoding, print hex dump 383 * at most 10 characters. 384 */ 385 for (i = 0; i < optlen && i < 10; i++) 386 printf("%02x", ((u_char *)(dh6o + 1))[i]); 387 break; 388 case DH6OPT_RECONF_MSG: 389 tp = (u_char *)(dh6o + 1); 390 switch (*tp) { 391 case DH6_RENEW: 392 printf(" for renew)"); 393 break; 394 case DH6_INFORM_REQ: 395 printf(" for inf-req)"); 396 break; 397 default: 398 printf(" for ?\?\?(%02x))", *tp); 399 break; 400 } 401 break; 402 case DH6OPT_RECONF_ACCEPT: /* nothing todo */ 403 printf(")"); 404 break; 405 case DH6OPT_SIP_SERVER_A: 406 case DH6OPT_DNS: 407 case DH6OPT_NTP_SERVERS: 408 if (optlen % 16) { 409 printf(" ?)"); 410 break; 411 } 412 tp = (u_char *)(dh6o + 1); 413 for (i = 0; i < optlen; i += 16) 414 printf(" %s", ip6addr_string(&tp[i])); 415 printf(")"); 416 break; 417 case DH6OPT_PREFIX_DELEGATION: 418 dhcp6opt_print((u_char *)(dh6o + 1), 419 (u_char *)(dh6o + 1) + optlen); 420 printf(")"); 421 break; 422 case DH6OPT_PREFIX_INFORMATION: 423 if (optlen % 21) 424 printf(" ?)"); 425 memcpy(&addr6, (u_char *)(dh6o + 1) + 5, 426 sizeof(addr6)); 427 printf(" %s/%d", ip6addr_string(&addr6), 428 (int)*((u_char *)(dh6o + 1) + 4)); 429 memcpy(&val32, dh6o + 1, sizeof(val32)); 430 val32 = ntohl(val32); 431 if (val32 == DHCP6_DURATITION_INFINITE) 432 printf(" lease-duration: infinite)"); 433 else 434 printf(" lease-duration: %u)", val32); 435 break; 436 case DH6OPT_STATUS_CODE: 437 if (optlen < 2) { 438 printf(" ?)"); 439 break; 440 } 441 memcpy(&val16, (u_char *)(dh6o + 1), sizeof(val16)); 442 val16 = ntohs(val16); 443 printf(" %s)", dhcp6stcode(val16)); 444 break; 445 case DH6OPT_IA_NA: 446 case DH6OPT_IA_PD: 447 if (optlen < sizeof(ia) - 4) { 448 printf(" ?)"); 449 break; 450 } 451 memcpy(&ia, (u_char *)dh6o, sizeof(ia)); 452 ia.dh6opt_ia_iaid = ntohl(ia.dh6opt_ia_iaid); 453 ia.dh6opt_ia_t1 = ntohl(ia.dh6opt_ia_t1); 454 ia.dh6opt_ia_t2 = ntohl(ia.dh6opt_ia_t2); 455 printf(" IAID:%lu T1:%lu T2:%lu", 456 (unsigned long)ia.dh6opt_ia_iaid, 457 (unsigned long)ia.dh6opt_ia_t1, 458 (unsigned long)ia.dh6opt_ia_t2); 459 if (optlen > sizeof(ia) - 4) { 460 /* there are sub-options */ 461 dhcp6opt_print((u_char *)dh6o + sizeof(ia), 462 (u_char *)(dh6o + 1) + optlen); 463 } 464 printf(")"); 465 break; 466 case DH6OPT_IA_PD_PREFIX: 467 if (optlen < sizeof(ia_prefix) - 4) { 468 printf(" ?)"); 469 break; 470 } 471 memcpy(&ia_prefix, (u_char *)dh6o, sizeof(ia_prefix)); 472 printf(" %s/%d", 473 ip6addr_string(&ia_prefix.dh6opt_ia_prefix_addr), 474 ia_prefix.dh6opt_ia_prefix_plen); 475 ia_prefix.dh6opt_ia_prefix_pltime = 476 ntohl(ia_prefix.dh6opt_ia_prefix_pltime); 477 ia_prefix.dh6opt_ia_prefix_vltime = 478 ntohl(ia_prefix.dh6opt_ia_prefix_vltime); 479 printf(" pltime:%lu vltime:%lu", 480 (unsigned long)ia_prefix.dh6opt_ia_prefix_pltime, 481 (unsigned long)ia_prefix.dh6opt_ia_prefix_vltime); 482 if (optlen > sizeof(ia_prefix) - 4) { 483 /* there are sub-options */ 484 dhcp6opt_print((u_char *)dh6o + 485 sizeof(ia_prefix), 486 (u_char *)(dh6o + 1) + optlen); 487 } 488 printf(")"); 489 break; 490 default: 491 printf(")"); 492 break; 493 } 494 495 cp += sizeof(*dh6o) + optlen; 496 } 497 return; 498 499 trunc: 500 printf("[|dhcp6ext]"); 501 } 502 503 /* 504 * Print dhcp6 packets 505 */ 506 void 507 dhcp6_print(const u_char *cp, u_int length) 508 { 509 struct dhcp6 *dh6; 510 struct dhcp6_relay *dh6relay; 511 const u_char *ep; 512 u_char *extp; 513 const char *name; 514 515 printf("dhcp6"); 516 517 ep = (u_char *)snapend; 518 if (cp + length < ep) 519 ep = cp + length; 520 521 dh6 = (struct dhcp6 *)cp; 522 dh6relay = (struct dhcp6_relay *)cp; 523 TCHECK(dh6->dh6_xid); 524 switch (dh6->dh6_msgtype) { 525 case DH6_SOLICIT: 526 name = "solicit"; 527 break; 528 case DH6_ADVERTISE: 529 name = "advertise"; 530 break; 531 case DH6_REQUEST: 532 name = "request"; 533 break; 534 case DH6_CONFIRM: 535 name = "confirm"; 536 break; 537 case DH6_RENEW: 538 name = "renew"; 539 break; 540 case DH6_REBIND: 541 name = "rebind"; 542 break; 543 case DH6_REPLY: 544 name = "reply"; 545 break; 546 case DH6_RELEASE: 547 name = "release"; 548 break; 549 case DH6_DECLINE: 550 name = "decline"; 551 break; 552 case DH6_RECONFIGURE: 553 name = "reconfigure"; 554 break; 555 case DH6_INFORM_REQ: 556 name= "inf-req"; 557 break; 558 case DH6_RELAY_FORW: 559 name= "relay-fwd"; 560 break; 561 case DH6_RELAY_REPLY: 562 name= "relay-reply"; 563 break; 564 default: 565 name = NULL; 566 break; 567 } 568 569 if (!vflag) { 570 if (name) 571 printf(" %s", name); 572 else if (dh6->dh6_msgtype != DH6_RELAY_FORW && 573 dh6->dh6_msgtype != DH6_RELAY_REPLY) { 574 printf(" msgtype-%u", dh6->dh6_msgtype); 575 } 576 return; 577 } 578 579 /* XXX relay agent messages have to be handled differently */ 580 581 if (name) 582 printf(" %s (", name); /*)*/ 583 else 584 printf(" msgtype-%u (", dh6->dh6_msgtype); /*)*/ 585 if (dh6->dh6_msgtype != DH6_RELAY_FORW && 586 dh6->dh6_msgtype != DH6_RELAY_REPLY) { 587 printf("xid=%x", EXTRACT_32BITS(&dh6->dh6_xid) & DH6_XIDMASK); 588 extp = (u_char *)(dh6 + 1); 589 dhcp6opt_print(extp, ep); 590 } else { /* relay messages */ 591 struct in6_addr addr6; 592 593 TCHECK(dh6relay->dh6relay_peeraddr); 594 595 memcpy(&addr6, dh6relay->dh6relay_linkaddr, sizeof (addr6)); 596 printf("linkaddr=%s", ip6addr_string(&addr6)); 597 598 memcpy(&addr6, dh6relay->dh6relay_peeraddr, sizeof (addr6)); 599 printf(" peeraddr=%s", ip6addr_string(&addr6)); 600 601 dhcp6opt_print((u_char *)(dh6relay + 1), ep); 602 } 603 /*(*/ 604 printf(")"); 605 return; 606 607 trunc: 608 printf("[|dhcp6]"); 609 } 610