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 #ifndef lint 11 static const char rcsid[] _U_ = 12 "@(#) $Header: /tcpdump/master/tcpdump/print-dccp.c,v 1.7.2.1 2007-11-09 00:45:16 guy Exp $ (LBL)"; 13 #endif 14 15 #ifdef HAVE_CONFIG_H 16 #include "config.h" 17 #endif 18 19 #include <tcpdump-stdinc.h> 20 21 #include "dccp.h" 22 23 #include <stdio.h> 24 #include <string.h> 25 26 #include "interface.h" 27 #include "addrtoname.h" 28 #include "extract.h" /* must come after interface.h */ 29 #include "ip.h" 30 #ifdef INET6 31 #include "ip6.h" 32 #endif 33 #include "ipproto.h" 34 35 static const char *dccp_reset_codes[] = { 36 "unspecified", 37 "closed", 38 "aborted", 39 "no_connection", 40 "packet_error", 41 "option_error", 42 "mandatory_error", 43 "connection_refused", 44 "bad_service_code", 45 "too_busy", 46 "bad_init_cookie", 47 "aggression_penalty", 48 }; 49 50 static const char *dccp_feature_nums[] = { 51 "reserved", 52 "ccid", 53 "allow_short_seqno", 54 "sequence_window", 55 "ecn_incapable", 56 "ack_ratio", 57 "send_ack_vector", 58 "send_ndp_count", 59 "minimum checksum coverage", 60 "check data checksum", 61 }; 62 63 static inline int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len) 64 { 65 u_int cov; 66 67 if (DCCPH_CSCOV(dh) == 0) 68 return len; 69 cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(u_int32_t); 70 return (cov > len)? len : cov; 71 } 72 73 static int dccp_cksum(const struct ip *ip, 74 const struct dccp_hdr *dh, u_int len) 75 { 76 int cov = dccp_csum_coverage(dh, len); 77 union phu { 78 struct phdr { 79 u_int32_t src; 80 u_int32_t dst; 81 u_char mbz; 82 u_char proto; 83 u_int16_t len; 84 } ph; 85 u_int16_t pa[6]; 86 } phu; 87 const u_int16_t *sp; 88 89 /* pseudo-header.. */ 90 phu.ph.mbz = 0; 91 phu.ph.len = htons(len); 92 phu.ph.proto = IPPROTO_DCCP; 93 memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t)); 94 if (IP_HL(ip) == 5) 95 memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t)); 96 else 97 phu.ph.dst = ip_finddst(ip); 98 99 sp = &phu.pa[0]; 100 return in_cksum((u_short *)dh, cov, sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]); 101 } 102 103 #ifdef INET6 104 static int dccp6_cksum(const struct ip6_hdr *ip6, const struct dccp_hdr *dh, u_int len) 105 { 106 size_t i; 107 u_int32_t sum = 0; 108 int cov = dccp_csum_coverage(dh, len); 109 union { 110 struct { 111 struct in6_addr ph_src; 112 struct in6_addr ph_dst; 113 u_int32_t ph_len; 114 u_int8_t ph_zero[3]; 115 u_int8_t ph_nxt; 116 } ph; 117 u_int16_t pa[20]; 118 } phu; 119 120 /* pseudo-header */ 121 memset(&phu, 0, sizeof(phu)); 122 phu.ph.ph_src = ip6->ip6_src; 123 phu.ph.ph_dst = ip6->ip6_dst; 124 phu.ph.ph_len = htonl(len); 125 phu.ph.ph_nxt = IPPROTO_DCCP; 126 127 for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) 128 sum += phu.pa[i]; 129 130 return in_cksum((u_short *)dh, cov, sum); 131 } 132 #endif 133 134 static const char *dccp_reset_code(u_int8_t code) 135 { 136 if (code >= __DCCP_RESET_CODE_LAST) 137 return "invalid"; 138 return dccp_reset_codes[code]; 139 } 140 141 static u_int64_t dccp_seqno(const struct dccp_hdr *dh) 142 { 143 u_int32_t seq_high = DCCPH_SEQ(dh); 144 u_int64_t seqno = EXTRACT_24BITS(&seq_high) & 0xFFFFFF; 145 146 if (DCCPH_X(dh) != 0) { 147 const struct dccp_hdr_ext *dhx = (void *)(dh + 1); 148 u_int32_t seq_low = dhx->dccph_seq_low; 149 seqno &= 0x00FFFF; /* clear reserved field */ 150 seqno = (seqno << 32) + EXTRACT_32BITS(&seq_low); 151 } 152 153 return seqno; 154 } 155 156 static inline unsigned int dccp_basic_hdr_len(const struct dccp_hdr *dh) 157 { 158 return sizeof(*dh) + (DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : 0); 159 } 160 161 static void dccp_print_ack_no(const u_char *bp) 162 { 163 const struct dccp_hdr *dh = (const struct dccp_hdr *)bp; 164 const struct dccp_hdr_ack_bits *dh_ack = 165 (struct dccp_hdr_ack_bits *)(bp + dccp_basic_hdr_len(dh)); 166 u_int32_t ack_high; 167 u_int64_t ackno; 168 169 TCHECK2(*dh_ack,4); 170 ack_high = DCCPH_ACK(dh_ack); 171 ackno = EXTRACT_24BITS(&ack_high) & 0xFFFFFF; 172 173 if (DCCPH_X(dh) != 0) { 174 u_int32_t ack_low; 175 176 TCHECK2(*dh_ack,8); 177 ack_low = dh_ack->dccph_ack_nr_low; 178 179 ackno &= 0x00FFFF; /* clear reserved field */ 180 ackno = (ackno << 32) + EXTRACT_32BITS(&ack_low); 181 } 182 183 (void)printf("(ack=%" PRIu64 ") ", ackno); 184 trunc: 185 return; 186 } 187 188 static inline unsigned int dccp_packet_hdr_len(const u_int8_t type) 189 { 190 if (type == DCCP_PKT_DATA) 191 return 0; 192 if (type == DCCP_PKT_DATAACK || 193 type == DCCP_PKT_ACK || 194 type == DCCP_PKT_SYNC || 195 type == DCCP_PKT_SYNCACK || 196 type == DCCP_PKT_CLOSE || 197 type == DCCP_PKT_CLOSEREQ) 198 return sizeof(struct dccp_hdr_ack_bits); 199 if (type == DCCP_PKT_REQUEST) 200 return sizeof(struct dccp_hdr_request); 201 if (type == DCCP_PKT_RESPONSE) 202 return sizeof(struct dccp_hdr_response); 203 return sizeof(struct dccp_hdr_reset); 204 } 205 206 static int dccp_print_option(const u_char *option); 207 208 /** 209 * dccp_print - show dccp packet 210 * @bp - beginning of dccp packet 211 * @data2 - beginning of enclosing 212 * @len - lenght of ip packet 213 */ 214 void dccp_print(const u_char *bp, const u_char *data2, u_int len) 215 { 216 const struct dccp_hdr *dh; 217 const struct ip *ip; 218 #ifdef INET6 219 const struct ip6_hdr *ip6; 220 #endif 221 const u_char *cp; 222 u_short sport, dport; 223 u_int hlen; 224 u_int extlen = 0; 225 226 dh = (const struct dccp_hdr *)bp; 227 228 ip = (struct ip *)data2; 229 #ifdef INET6 230 if (IP_V(ip) == 6) 231 ip6 = (const struct ip6_hdr *)data2; 232 else 233 ip6 = NULL; 234 #endif /*INET6*/ 235 cp = (const u_char *)(dh + 1); 236 if (cp > snapend) { 237 printf("[Invalid packet|dccp]"); 238 return; 239 } 240 241 if (len < sizeof(struct dccp_hdr)) { 242 printf("truncated-dccp - %ld bytes missing!", 243 (long)len - sizeof(struct dccp_hdr)); 244 return; 245 } 246 247 sport = EXTRACT_16BITS(&dh->dccph_sport); 248 dport = EXTRACT_16BITS(&dh->dccph_dport); 249 hlen = dh->dccph_doff * 4; 250 251 #ifdef INET6 252 if (ip6) { 253 (void)printf("%s.%d > %s.%d: ", 254 ip6addr_string(&ip6->ip6_src), sport, 255 ip6addr_string(&ip6->ip6_dst), dport); 256 } else 257 #endif /*INET6*/ 258 { 259 (void)printf("%s.%d > %s.%d: ", 260 ipaddr_string(&ip->ip_src), sport, 261 ipaddr_string(&ip->ip_dst), dport); 262 } 263 fflush(stdout); 264 265 if (qflag) { 266 (void)printf(" %d", len - hlen); 267 if (hlen > len) { 268 (void)printf("dccp [bad hdr length %u - too long, > %u]", 269 hlen, len); 270 } 271 return; 272 } 273 274 /* other variables in generic header */ 275 if (vflag) { 276 (void)printf("CCVal %d, CsCov %d, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh)); 277 } 278 279 /* checksum calculation */ 280 if (vflag && TTEST2(bp[0], len)) { 281 u_int16_t sum = 0, dccp_sum; 282 283 dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum); 284 (void)printf("cksum 0x%04x ", dccp_sum); 285 if (IP_V(ip) == 4) 286 sum = dccp_cksum(ip, dh, len); 287 #ifdef INET6 288 else if (IP_V(ip) == 6) 289 sum = dccp6_cksum(ip6, dh, len); 290 #endif 291 if (sum != 0) 292 (void)printf("(incorrect -> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum)); 293 else 294 (void)printf("(correct), "); 295 } 296 297 switch (DCCPH_TYPE(dh)) { 298 case DCCP_PKT_REQUEST: { 299 struct dccp_hdr_request *dhr = 300 (struct dccp_hdr_request *)(bp + dccp_basic_hdr_len(dh)); 301 TCHECK(*dhr); 302 (void)printf("request (service=%d) ", 303 EXTRACT_32BITS(&dhr->dccph_req_service)); 304 extlen += 4; 305 break; 306 } 307 case DCCP_PKT_RESPONSE: { 308 struct dccp_hdr_response *dhr = 309 (struct dccp_hdr_response *)(bp + dccp_basic_hdr_len(dh)); 310 TCHECK(*dhr); 311 (void)printf("response (service=%d) ", 312 EXTRACT_32BITS(&dhr->dccph_resp_service)); 313 extlen += 12; 314 break; 315 } 316 case DCCP_PKT_DATA: 317 (void)printf("data "); 318 break; 319 case DCCP_PKT_ACK: { 320 (void)printf("ack "); 321 extlen += 8; 322 break; 323 } 324 case DCCP_PKT_DATAACK: { 325 (void)printf("dataack "); 326 extlen += 8; 327 break; 328 } 329 case DCCP_PKT_CLOSEREQ: 330 (void)printf("closereq "); 331 extlen += 8; 332 break; 333 case DCCP_PKT_CLOSE: 334 (void)printf("close "); 335 extlen += 8; 336 break; 337 case DCCP_PKT_RESET: { 338 struct dccp_hdr_reset *dhr = 339 (struct dccp_hdr_reset *)(bp + dccp_basic_hdr_len(dh)); 340 TCHECK(*dhr); 341 (void)printf("reset (code=%s) ", 342 dccp_reset_code(dhr->dccph_reset_code)); 343 extlen += 12; 344 break; 345 } 346 case DCCP_PKT_SYNC: 347 (void)printf("sync "); 348 extlen += 8; 349 break; 350 case DCCP_PKT_SYNCACK: 351 (void)printf("syncack "); 352 extlen += 8; 353 break; 354 default: 355 (void)printf("invalid "); 356 break; 357 } 358 359 if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) && 360 (DCCPH_TYPE(dh) != DCCP_PKT_REQUEST)) 361 dccp_print_ack_no(bp); 362 363 if (vflag < 2) 364 return; 365 366 (void)printf("seq %" PRIu64, dccp_seqno(dh)); 367 368 /* process options */ 369 if (hlen > dccp_basic_hdr_len(dh) + extlen){ 370 const u_char *cp; 371 u_int optlen; 372 cp = bp + dccp_basic_hdr_len(dh) + extlen; 373 printf(" <"); 374 375 hlen -= dccp_basic_hdr_len(dh) + extlen; 376 while(1){ 377 TCHECK(*cp); 378 optlen = dccp_print_option(cp); 379 if (!optlen) goto trunc2; 380 if (hlen <= optlen) break; 381 hlen -= optlen; 382 cp += optlen; 383 printf(", "); 384 } 385 printf(">"); 386 } 387 return; 388 trunc: 389 printf("[|dccp]"); 390 trunc2: 391 return; 392 } 393 394 static int dccp_print_option(const u_char *option) 395 { 396 u_int8_t optlen, i; 397 u_int32_t *ts; 398 u_int16_t *var16; 399 u_int32_t *var32; 400 401 TCHECK(*option); 402 403 if (*option >= 32) { 404 TCHECK(*(option+1)); 405 optlen = *(option +1); 406 if (optlen < 2) { 407 printf("Option %d optlen too short",*option); 408 return 1; 409 } 410 } else optlen = 1; 411 412 TCHECK2(*option,optlen); 413 414 switch (*option){ 415 case 0: 416 printf("nop"); 417 break; 418 case 1: 419 printf("mandatory"); 420 break; 421 case 2: 422 printf("slowreceiver"); 423 break; 424 case 32: 425 printf("change_l"); 426 if (*(option +2) < 10){ 427 printf(" %s", dccp_feature_nums[*(option +2)]); 428 for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i)); 429 } 430 break; 431 case 33: 432 printf("confirm_l"); 433 if (*(option +2) < 10){ 434 printf(" %s", dccp_feature_nums[*(option +2)]); 435 for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i)); 436 } 437 break; 438 case 34: 439 printf("change_r"); 440 if (*(option +2) < 10){ 441 printf(" %s", dccp_feature_nums[*(option +2)]); 442 for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i)); 443 } 444 break; 445 case 35: 446 printf("confirm_r"); 447 if (*(option +2) < 10){ 448 printf(" %s", dccp_feature_nums[*(option +2)]); 449 for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i)); 450 } 451 break; 452 case 36: 453 printf("initcookie 0x"); 454 for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i)); 455 break; 456 case 37: 457 printf("ndp_count"); 458 for (i = 0; i < optlen -2; i ++) printf(" %d", *(option +2 + i)); 459 break; 460 case 38: 461 printf("ack_vector0 0x"); 462 for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i)); 463 break; 464 case 39: 465 printf("ack_vector1 0x"); 466 for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i)); 467 break; 468 case 40: 469 printf("data_dropped 0x"); 470 for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i)); 471 break; 472 case 41: 473 ts = (u_int32_t *)(option + 2); 474 printf("timestamp %u", (u_int32_t)ntohl(*ts)); 475 break; 476 case 42: 477 ts = (u_int32_t *)(option + 2); 478 printf("timestamp_echo %u", (u_int32_t)ntohl(*ts)); 479 break; 480 case 43: 481 printf("elapsed_time "); 482 if (optlen == 6){ 483 ts = (u_int32_t *)(option + 2); 484 printf("%u", (u_int32_t)ntohl(*ts)); 485 } else { 486 var16 = (u_int16_t *)(option + 2); 487 printf("%u", ntohs(*var16)); 488 } 489 break; 490 case 44: 491 printf("data_checksum "); 492 for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i)); 493 break; 494 default : 495 if (*option >= 128) { 496 printf("CCID option %d",*option); 497 switch (optlen) { 498 case 4: 499 var16 = (u_int16_t *)(option + 2); 500 printf(" %u",ntohs(*var16)); 501 break; 502 case 6: 503 var32 = (u_int32_t *)(option + 2); 504 printf(" %u",(u_int32_t)ntohl(*var32)); 505 break; 506 default: 507 break; 508 } 509 break; 510 } 511 512 printf("unknown_opt %d", *option); 513 break; 514 } 515 516 return optlen; 517 trunc: 518 printf("[|dccp]"); 519 return 0; 520 } 521