1 /* 2 * Copyright (C) Arnaldo Carvalho de Melo 2004 3 * Copyright (C) Ian McDonald 2005 4 * Copyright (C) Yoshifumi Nishida 2005 5 * 6 * This software may be distributed either under the terms of the 7 * BSD-style license that accompanies tcpdump or the GNU GPL version 2 8 */ 9 10 #define NETDISSECT_REWORKED 11 #ifdef HAVE_CONFIG_H 12 #include "config.h" 13 #endif 14 15 #include <tcpdump-stdinc.h> 16 17 #include <stdio.h> 18 #include <string.h> 19 20 #include "interface.h" 21 #include "addrtoname.h" 22 #include "extract.h" /* must come after interface.h */ 23 #include "ip.h" 24 #ifdef INET6 25 #include "ip6.h" 26 #endif 27 #include "ipproto.h" 28 29 /** 30 * struct dccp_hdr - generic part of DCCP packet header, with a 24-bit 31 * sequence number 32 * 33 * @dccph_sport - Relevant port on the endpoint that sent this packet 34 * @dccph_dport - Relevant port on the other endpoint 35 * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words 36 * @dccph_ccval - Used by the HC-Sender CCID 37 * @dccph_cscov - Parts of the packet that are covered by the Checksum field 38 * @dccph_checksum - Internet checksum, depends on dccph_cscov 39 * @dccph_x - 0 = 24 bit sequence number, 1 = 48 40 * @dccph_type - packet type, see DCCP_PKT_ prefixed macros 41 * @dccph_seq - 24-bit sequence number 42 */ 43 struct dccp_hdr { 44 uint16_t dccph_sport, 45 dccph_dport; 46 uint8_t dccph_doff; 47 uint8_t dccph_ccval_cscov; 48 uint16_t dccph_checksum; 49 uint8_t dccph_xtr; 50 uint8_t dccph_seq[3]; 51 } UNALIGNED; 52 53 /** 54 * struct dccp_hdr_ext - generic part of DCCP packet header, with a 48-bit 55 * sequence number 56 * 57 * @dccph_sport - Relevant port on the endpoint that sent this packet 58 * @dccph_dport - Relevant port on the other endpoint 59 * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words 60 * @dccph_ccval - Used by the HC-Sender CCID 61 * @dccph_cscov - Parts of the packet that are covered by the Checksum field 62 * @dccph_checksum - Internet checksum, depends on dccph_cscov 63 * @dccph_x - 0 = 24 bit sequence number, 1 = 48 64 * @dccph_type - packet type, see DCCP_PKT_ prefixed macros 65 * @dccph_seq - 48-bit sequence number 66 */ 67 struct dccp_hdr_ext { 68 uint16_t dccph_sport, 69 dccph_dport; 70 uint8_t dccph_doff; 71 uint8_t dccph_ccval_cscov; 72 uint16_t dccph_checksum; 73 uint8_t dccph_xtr; 74 uint8_t reserved; 75 uint8_t dccph_seq[6]; 76 } UNALIGNED; 77 78 #define DCCPH_CCVAL(dh) (((dh)->dccph_ccval_cscov >> 4) & 0xF) 79 #define DCCPH_CSCOV(dh) (((dh)->dccph_ccval_cscov) & 0xF) 80 81 #define DCCPH_X(dh) ((dh)->dccph_xtr & 1) 82 #define DCCPH_TYPE(dh) (((dh)->dccph_xtr >> 1) & 0xF) 83 84 /** 85 * struct dccp_hdr_request - Conection initiation request header 86 * 87 * @dccph_req_service - Service to which the client app wants to connect 88 */ 89 struct dccp_hdr_request { 90 uint32_t dccph_req_service; 91 } UNALIGNED; 92 93 /** 94 * struct dccp_hdr_response - Conection initiation response header 95 * 96 * @dccph_resp_ack - 48 bit ack number, contains GSR 97 * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request 98 */ 99 struct dccp_hdr_response { 100 uint8_t dccph_resp_ack[8]; /* always 8 bytes */ 101 uint32_t dccph_resp_service; 102 } UNALIGNED; 103 104 /** 105 * struct dccp_hdr_reset - Unconditionally shut down a connection 106 * 107 * @dccph_resp_ack - 48 bit ack number 108 * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request 109 */ 110 struct dccp_hdr_reset { 111 uint8_t dccph_reset_ack[8]; /* always 8 bytes */ 112 uint8_t dccph_reset_code, 113 dccph_reset_data[3]; 114 } UNALIGNED; 115 116 enum dccp_pkt_type { 117 DCCP_PKT_REQUEST = 0, 118 DCCP_PKT_RESPONSE, 119 DCCP_PKT_DATA, 120 DCCP_PKT_ACK, 121 DCCP_PKT_DATAACK, 122 DCCP_PKT_CLOSEREQ, 123 DCCP_PKT_CLOSE, 124 DCCP_PKT_RESET, 125 DCCP_PKT_SYNC, 126 DCCP_PKT_SYNCACK, 127 DCCP_PKT_INVALID 128 }; 129 130 enum dccp_reset_codes { 131 DCCP_RESET_CODE_UNSPECIFIED = 0, 132 DCCP_RESET_CODE_CLOSED, 133 DCCP_RESET_CODE_ABORTED, 134 DCCP_RESET_CODE_NO_CONNECTION, 135 DCCP_RESET_CODE_PACKET_ERROR, 136 DCCP_RESET_CODE_OPTION_ERROR, 137 DCCP_RESET_CODE_MANDATORY_ERROR, 138 DCCP_RESET_CODE_CONNECTION_REFUSED, 139 DCCP_RESET_CODE_BAD_SERVICE_CODE, 140 DCCP_RESET_CODE_TOO_BUSY, 141 DCCP_RESET_CODE_BAD_INIT_COOKIE, 142 DCCP_RESET_CODE_AGGRESSION_PENALTY, 143 __DCCP_RESET_CODE_LAST 144 }; 145 146 static const char tstr[] = "[|dccp]"; 147 148 static const char *dccp_reset_codes[] = { 149 "unspecified", 150 "closed", 151 "aborted", 152 "no_connection", 153 "packet_error", 154 "option_error", 155 "mandatory_error", 156 "connection_refused", 157 "bad_service_code", 158 "too_busy", 159 "bad_init_cookie", 160 "aggression_penalty", 161 }; 162 163 static const char *dccp_feature_nums[] = { 164 "reserved", 165 "ccid", 166 "allow_short_seqno", 167 "sequence_window", 168 "ecn_incapable", 169 "ack_ratio", 170 "send_ack_vector", 171 "send_ndp_count", 172 "minimum checksum coverage", 173 "check data checksum", 174 }; 175 176 static inline u_int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len) 177 { 178 u_int cov; 179 180 if (DCCPH_CSCOV(dh) == 0) 181 return len; 182 cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(uint32_t); 183 return (cov > len)? len : cov; 184 } 185 186 static int dccp_cksum(netdissect_options *ndo, const struct ip *ip, 187 const struct dccp_hdr *dh, u_int len) 188 { 189 return nextproto4_cksum(ndo, ip, (const uint8_t *)(void *)dh, len, 190 dccp_csum_coverage(dh, len), IPPROTO_DCCP); 191 } 192 193 #ifdef INET6 194 static int dccp6_cksum(const struct ip6_hdr *ip6, const struct dccp_hdr *dh, u_int len) 195 { 196 return nextproto6_cksum(ip6, (const uint8_t *)(void *)dh, len, 197 dccp_csum_coverage(dh, len), IPPROTO_DCCP); 198 } 199 #endif 200 201 static const char *dccp_reset_code(uint8_t code) 202 { 203 if (code >= __DCCP_RESET_CODE_LAST) 204 return "invalid"; 205 return dccp_reset_codes[code]; 206 } 207 208 static uint64_t dccp_seqno(const u_char *bp) 209 { 210 const struct dccp_hdr *dh = (const struct dccp_hdr *)bp; 211 uint64_t seqno; 212 213 if (DCCPH_X(dh) != 0) { 214 const struct dccp_hdr_ext *dhx = (const struct dccp_hdr_ext *)bp; 215 seqno = EXTRACT_48BITS(dhx->dccph_seq); 216 } else { 217 seqno = EXTRACT_24BITS(dh->dccph_seq); 218 } 219 220 return seqno; 221 } 222 223 static inline unsigned int dccp_basic_hdr_len(const struct dccp_hdr *dh) 224 { 225 return DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : sizeof(struct dccp_hdr); 226 } 227 228 static void dccp_print_ack_no(netdissect_options *ndo, const u_char *bp) 229 { 230 const struct dccp_hdr *dh = (const struct dccp_hdr *)bp; 231 const u_char *ackp = bp + dccp_basic_hdr_len(dh); 232 uint64_t ackno; 233 234 if (DCCPH_X(dh) != 0) { 235 ND_TCHECK2(*ackp, 8); 236 ackno = EXTRACT_48BITS(ackp + 2); 237 } else { 238 ND_TCHECK2(*ackp, 4); 239 ackno = EXTRACT_24BITS(ackp + 1); 240 } 241 242 ND_PRINT((ndo, "(ack=%" PRIu64 ") ", ackno)); 243 trunc: 244 return; 245 } 246 247 static int dccp_print_option(netdissect_options *, const u_char *, u_int); 248 249 /** 250 * dccp_print - show dccp packet 251 * @bp - beginning of dccp packet 252 * @data2 - beginning of enclosing 253 * @len - lenght of ip packet 254 */ 255 void dccp_print(netdissect_options *ndo, const u_char *bp, const u_char *data2, 256 u_int len) 257 { 258 const struct dccp_hdr *dh; 259 const struct ip *ip; 260 #ifdef INET6 261 const struct ip6_hdr *ip6; 262 #endif 263 const u_char *cp; 264 u_short sport, dport; 265 u_int hlen; 266 u_int fixed_hdrlen; 267 268 dh = (const struct dccp_hdr *)bp; 269 270 ip = (struct ip *)data2; 271 #ifdef INET6 272 if (IP_V(ip) == 6) 273 ip6 = (const struct ip6_hdr *)data2; 274 else 275 ip6 = NULL; 276 #endif /*INET6*/ 277 278 /* make sure we have enough data to look at the X bit */ 279 cp = (const u_char *)(dh + 1); 280 if (cp > ndo->ndo_snapend) { 281 ND_PRINT((ndo, "[Invalid packet|dccp]")); 282 return; 283 } 284 if (len < sizeof(struct dccp_hdr)) { 285 ND_PRINT((ndo, "truncated-dccp - %u bytes missing!", 286 len - (u_int)sizeof(struct dccp_hdr))); 287 return; 288 } 289 290 /* get the length of the generic header */ 291 fixed_hdrlen = dccp_basic_hdr_len(dh); 292 if (len < fixed_hdrlen) { 293 ND_PRINT((ndo, "truncated-dccp - %u bytes missing!", 294 len - fixed_hdrlen)); 295 return; 296 } 297 ND_TCHECK2(*dh, fixed_hdrlen); 298 299 sport = EXTRACT_16BITS(&dh->dccph_sport); 300 dport = EXTRACT_16BITS(&dh->dccph_dport); 301 hlen = dh->dccph_doff * 4; 302 303 #ifdef INET6 304 if (ip6) { 305 ND_PRINT((ndo, "%s.%d > %s.%d: ", 306 ip6addr_string(ndo, &ip6->ip6_src), sport, 307 ip6addr_string(ndo, &ip6->ip6_dst), dport)); 308 } else 309 #endif /*INET6*/ 310 { 311 ND_PRINT((ndo, "%s.%d > %s.%d: ", 312 ipaddr_string(ndo, &ip->ip_src), sport, 313 ipaddr_string(ndo, &ip->ip_dst), dport)); 314 } 315 316 if (ndo->ndo_qflag) { 317 ND_PRINT((ndo, " %d", len - hlen)); 318 if (hlen > len) { 319 ND_PRINT((ndo, "dccp [bad hdr length %u - too long, > %u]", 320 hlen, len)); 321 } 322 return; 323 } 324 325 /* other variables in generic header */ 326 if (ndo->ndo_vflag) { 327 ND_PRINT((ndo, "CCVal %d, CsCov %d, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh))); 328 } 329 330 /* checksum calculation */ 331 if (ndo->ndo_vflag && ND_TTEST2(bp[0], len)) { 332 uint16_t sum = 0, dccp_sum; 333 334 dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum); 335 ND_PRINT((ndo, "cksum 0x%04x ", dccp_sum)); 336 if (IP_V(ip) == 4) 337 sum = dccp_cksum(ndo, ip, dh, len); 338 #ifdef INET6 339 else if (IP_V(ip) == 6) 340 sum = dccp6_cksum(ip6, dh, len); 341 #endif 342 if (sum != 0) 343 ND_PRINT((ndo, "(incorrect -> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum))); 344 else 345 ND_PRINT((ndo, "(correct), ")); 346 } 347 348 switch (DCCPH_TYPE(dh)) { 349 case DCCP_PKT_REQUEST: { 350 struct dccp_hdr_request *dhr = 351 (struct dccp_hdr_request *)(bp + fixed_hdrlen); 352 fixed_hdrlen += 4; 353 if (len < fixed_hdrlen) { 354 ND_PRINT((ndo, "truncated-dccp request - %u bytes missing!", 355 len - fixed_hdrlen)); 356 return; 357 } 358 ND_TCHECK(*dhr); 359 ND_PRINT((ndo, "request (service=%d) ", 360 EXTRACT_32BITS(&dhr->dccph_req_service))); 361 break; 362 } 363 case DCCP_PKT_RESPONSE: { 364 struct dccp_hdr_response *dhr = 365 (struct dccp_hdr_response *)(bp + fixed_hdrlen); 366 fixed_hdrlen += 12; 367 if (len < fixed_hdrlen) { 368 ND_PRINT((ndo, "truncated-dccp response - %u bytes missing!", 369 len - fixed_hdrlen)); 370 return; 371 } 372 ND_TCHECK(*dhr); 373 ND_PRINT((ndo, "response (service=%d) ", 374 EXTRACT_32BITS(&dhr->dccph_resp_service))); 375 break; 376 } 377 case DCCP_PKT_DATA: 378 ND_PRINT((ndo, "data ")); 379 break; 380 case DCCP_PKT_ACK: { 381 fixed_hdrlen += 8; 382 if (len < fixed_hdrlen) { 383 ND_PRINT((ndo, "truncated-dccp ack - %u bytes missing!", 384 len - fixed_hdrlen)); 385 return; 386 } 387 ND_PRINT((ndo, "ack ")); 388 break; 389 } 390 case DCCP_PKT_DATAACK: { 391 fixed_hdrlen += 8; 392 if (len < fixed_hdrlen) { 393 ND_PRINT((ndo, "truncated-dccp dataack - %u bytes missing!", 394 len - fixed_hdrlen)); 395 return; 396 } 397 ND_PRINT((ndo, "dataack ")); 398 break; 399 } 400 case DCCP_PKT_CLOSEREQ: 401 fixed_hdrlen += 8; 402 if (len < fixed_hdrlen) { 403 ND_PRINT((ndo, "truncated-dccp closereq - %u bytes missing!", 404 len - fixed_hdrlen)); 405 return; 406 } 407 ND_PRINT((ndo, "closereq ")); 408 break; 409 case DCCP_PKT_CLOSE: 410 fixed_hdrlen += 8; 411 if (len < fixed_hdrlen) { 412 ND_PRINT((ndo, "truncated-dccp close - %u bytes missing!", 413 len - fixed_hdrlen)); 414 return; 415 } 416 ND_PRINT((ndo, "close ")); 417 break; 418 case DCCP_PKT_RESET: { 419 struct dccp_hdr_reset *dhr = 420 (struct dccp_hdr_reset *)(bp + fixed_hdrlen); 421 fixed_hdrlen += 12; 422 if (len < fixed_hdrlen) { 423 ND_PRINT((ndo, "truncated-dccp reset - %u bytes missing!", 424 len - fixed_hdrlen)); 425 return; 426 } 427 ND_TCHECK(*dhr); 428 ND_PRINT((ndo, "reset (code=%s) ", 429 dccp_reset_code(dhr->dccph_reset_code))); 430 break; 431 } 432 case DCCP_PKT_SYNC: 433 fixed_hdrlen += 8; 434 if (len < fixed_hdrlen) { 435 ND_PRINT((ndo, "truncated-dccp sync - %u bytes missing!", 436 len - fixed_hdrlen)); 437 return; 438 } 439 ND_PRINT((ndo, "sync ")); 440 break; 441 case DCCP_PKT_SYNCACK: 442 fixed_hdrlen += 8; 443 if (len < fixed_hdrlen) { 444 ND_PRINT((ndo, "truncated-dccp syncack - %u bytes missing!", 445 len - fixed_hdrlen)); 446 return; 447 } 448 ND_PRINT((ndo, "syncack ")); 449 break; 450 default: 451 ND_PRINT((ndo, "invalid ")); 452 break; 453 } 454 455 if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) && 456 (DCCPH_TYPE(dh) != DCCP_PKT_REQUEST)) 457 dccp_print_ack_no(ndo, bp); 458 459 if (ndo->ndo_vflag < 2) 460 return; 461 462 ND_PRINT((ndo, "seq %" PRIu64, dccp_seqno(bp))); 463 464 /* process options */ 465 if (hlen > fixed_hdrlen){ 466 const u_char *cp; 467 u_int optlen; 468 cp = bp + fixed_hdrlen; 469 ND_PRINT((ndo, " <")); 470 471 hlen -= fixed_hdrlen; 472 while(1){ 473 optlen = dccp_print_option(ndo, cp, hlen); 474 if (!optlen) 475 break; 476 if (hlen <= optlen) 477 break; 478 hlen -= optlen; 479 cp += optlen; 480 ND_PRINT((ndo, ", ")); 481 } 482 ND_PRINT((ndo, ">")); 483 } 484 return; 485 trunc: 486 ND_PRINT((ndo, "%s", tstr)); 487 return; 488 } 489 490 static const struct tok dccp_option_values[] = { 491 { 0, "nop" }, 492 { 1, "mandatory" }, 493 { 2, "slowreceiver" }, 494 { 32, "change_l" }, 495 { 33, "confirm_l" }, 496 { 34, "change_r" }, 497 { 35, "confirm_r" }, 498 { 36, "initcookie" }, 499 { 37, "ndp_count" }, 500 { 38, "ack_vector0" }, 501 { 39, "ack_vector1" }, 502 { 40, "data_dropped" }, 503 { 41, "timestamp" }, 504 { 42, "timestamp_echo" }, 505 { 43, "elapsed_time" }, 506 { 44, "data_checksum" }, 507 { 0, NULL } 508 }; 509 510 static int dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen) 511 { 512 uint8_t optlen, i; 513 514 ND_TCHECK(*option); 515 516 if (*option >= 32) { 517 ND_TCHECK(*(option+1)); 518 optlen = *(option +1); 519 if (optlen < 2) { 520 if (*option >= 128) 521 ND_PRINT((ndo, "CCID option %u optlen too short", *option)); 522 else 523 ND_PRINT((ndo, "%s optlen too short", 524 tok2str(dccp_option_values, "Option %u", *option))); 525 return 0; 526 } 527 } else 528 optlen = 1; 529 530 if (hlen < optlen) { 531 if (*option >= 128) 532 ND_PRINT((ndo, "CCID option %u optlen goes past header length", 533 *option)); 534 else 535 ND_PRINT((ndo, "%s optlen goes past header length", 536 tok2str(dccp_option_values, "Option %u", *option))); 537 return 0; 538 } 539 ND_TCHECK2(*option, optlen); 540 541 if (*option >= 128) { 542 ND_PRINT((ndo, "CCID option %d", *option)); 543 switch (optlen) { 544 case 4: 545 ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2))); 546 break; 547 case 6: 548 ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2))); 549 break; 550 default: 551 break; 552 } 553 } else { 554 ND_PRINT((ndo, "%s", tok2str(dccp_option_values, "Option %u", *option))); 555 switch (*option) { 556 case 32: 557 case 33: 558 case 34: 559 case 35: 560 if (optlen < 3) { 561 ND_PRINT((ndo, " optlen too short")); 562 return optlen; 563 } 564 if (*(option + 2) < 10){ 565 ND_PRINT((ndo, " %s", dccp_feature_nums[*(option + 2)])); 566 for (i = 0; i < optlen - 3; i++) 567 ND_PRINT((ndo, " %d", *(option + 3 + i))); 568 } 569 break; 570 case 36: 571 if (optlen > 2) { 572 ND_PRINT((ndo, " 0x")); 573 for (i = 0; i < optlen - 2; i++) 574 ND_PRINT((ndo, "%02x", *(option + 2 + i))); 575 } 576 break; 577 case 37: 578 for (i = 0; i < optlen - 2; i++) 579 ND_PRINT((ndo, " %d", *(option + 2 + i))); 580 break; 581 case 38: 582 if (optlen > 2) { 583 ND_PRINT((ndo, " 0x")); 584 for (i = 0; i < optlen - 2; i++) 585 ND_PRINT((ndo, "%02x", *(option + 2 + i))); 586 } 587 break; 588 case 39: 589 if (optlen > 2) { 590 ND_PRINT((ndo, " 0x")); 591 for (i = 0; i < optlen - 2; i++) 592 ND_PRINT((ndo, "%02x", *(option + 2 + i))); 593 } 594 break; 595 case 40: 596 if (optlen > 2) { 597 ND_PRINT((ndo, " 0x")); 598 for (i = 0; i < optlen - 2; i++) 599 ND_PRINT((ndo, "%02x", *(option + 2 + i))); 600 } 601 break; 602 case 41: 603 if (optlen == 4) 604 ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2))); 605 else 606 ND_PRINT((ndo, " optlen != 4")); 607 break; 608 case 42: 609 if (optlen == 4) 610 ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2))); 611 else 612 ND_PRINT((ndo, " optlen != 4")); 613 break; 614 case 43: 615 if (optlen == 6) 616 ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2))); 617 else if (optlen == 4) 618 ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2))); 619 else 620 ND_PRINT((ndo, " optlen != 4 or 6")); 621 break; 622 case 44: 623 if (optlen > 2) { 624 ND_PRINT((ndo, " ")); 625 for (i = 0; i < optlen - 2; i++) 626 ND_PRINT((ndo, "%02x", *(option + 2 + i))); 627 } 628 break; 629 } 630 } 631 632 return optlen; 633 trunc: 634 ND_PRINT((ndo, "%s", tstr)); 635 return 0; 636 } 637