1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  24  * Copyright 2012 David Hoeppner.  All rights reserved.
  25  */
  26 
  27 #include <stdio.h>
  28 #include <ctype.h>
  29 #include <string.h>
  30 #include <fcntl.h>
  31 #include <string.h>
  32 #include <sys/types.h>
  33 #include <sys/time.h>
  34 
  35 #include <sys/socket.h>
  36 #include <sys/sockio.h>
  37 #include <net/if.h>
  38 #include <netinet/in_systm.h>
  39 #include <netinet/in.h>
  40 #include <netinet/ip.h>
  41 #include <netinet/if_ether.h>
  42 #include <netinet/dccp.h>
  43 #include "snoop.h"
  44 
  45 /*
  46  * Snoop interpreter for DCCP (RFC4340)
  47  *
  48  */
  49 
  50 extern char *dlc_header;
  51 
  52 static char     *get_type(uint8_t);
  53 static void     print_dccpoptions_summary(uchar_t *, uchar_t *);
  54 static void     print_dccpoptions(uchar_t *, uchar_t *);
  55 
  56 static char *
  57 get_type(uint8_t type)
  58 {
  59         switch (type) {
  60         case 0:
  61                 return ("DCCP-Request");
  62         case 1:
  63                 return ("DCCP-Response");
  64         case 2:
  65                 return ("DCCP-Data");
  66         case 3:
  67                 return ("DCCP-Ack");
  68         case 4:
  69                 return ("DCCP-DataAck");
  70         case 5:
  71                 return ("DCCP-CloseReq");
  72         case 6:
  73                 return ("DCCP-Close");
  74         case 7:
  75                 return ("DCCP-Reset");
  76         case 8:
  77                 return ("DCCP-Sync");
  78         case 9:
  79                 return ("DCCP-SyncAck");
  80         case 10 ... 15:
  81                 return ("Reserved");
  82 
  83         default:
  84                 return ("Unknown");
  85         }
  86 }
  87 
  88 int
  89 interpret_dccp(int flags, struct dccphdr *dccp, int iplen, int fraglen)
  90 {
  91         char            *data;
  92         char            *line;
  93         char            *endline;
  94         uint64_t        seq;
  95         uint64_t        ack;
  96         int             hdrlen;
  97         int             dccplen;
  98         int             option_offset;
  99         int             i;
 100 
 101         hdrlen = dccp->dh_offset * 4;
 102         data = (char *)dccp + hdrlen;
 103         dccplen = iplen - hdrlen;
 104         fraglen -= hdrlen;
 105 
 106         if (fraglen < 0) {
 107                 return (fraglen + hdrlen);      /* Incomplete header */
 108         }
 109 
 110         if (fraglen > dccplen) {
 111                 fraglen = dccplen;
 112         }
 113 
 114         if (dccp->dh_x == 1) {
 115                 switch (dccp->dh_type) {
 116                 case 0:         /* DCCP-Request */
 117                         option_offset = 20;
 118                         break;
 119                 case 1:         /* DCCP-Response */
 120                         option_offset = 28;
 121                         break;
 122                 case 7:         /* DCCP-Reset */
 123                         option_offset = 28;
 124                         break;
 125                 case 8:         /* DCCP-Sync */
 126                 case 9:         /* DCCP-SyncAck */
 127                         option_offset = 24;
 128                         break;
 129 
 130                 default:
 131                         option_offset = 20;
 132                         break;
 133                 }
 134 
 135                 /* Sequence number */
 136                 seq = ntohs(dccp->dh_seq);
 137                 seq <<= 32;
 138                 seq += (uint32_t)dccp + sizeof (struct dccphdr);
 139 
 140                 ack = (uint32_t)(dccp + 16) & 0xffff;
 141         } else {
 142                 switch (dccp->dh_type) {
 143                 case 0:         /* DCCP-Request */
 144                 case 1:         /* DCCP-Response */
 145                 case 7:         /* DCCP-Reset */
 146                 case 8:         /* DCCP-Sync */
 147                 case 9:         /* DCCP-SyncAck */
 148                         break;
 149 
 150                 default:
 151                         option_offset = 20;
 152                         break;
 153                 }
 154 
 155                 /* Sequence number */
 156                 seq = dccp->dh_res_seq << 16;
 157                 seq |= ntohs(dccp->dh_seq);
 158         }
 159 
 160         if (flags & F_SUM) {
 161                 line = get_sum_line();
 162                 endline = line + MAXLINE;
 163 
 164                 (void) snprintf(line, endline - line, "DCCP D=%d S=%d",
 165                     ntohs(dccp->dh_dport), ntohs(dccp->dh_sport));
 166                 line += strlen(line);
 167 
 168                 (void) snprintf(line, endline - line, "CCval=%d CsCov=%d",
 169                     dccp->dh_ccval, dccp->dh_cscov);
 170 
 171                 (void) snprintf(line, endline - line, " Seq=%u Len=%d",
 172                     seq, dccplen);
 173                 line += strlen(line);
 174 
 175                 /*
 176                  * All packets except DCCP-Request and DCCP-Data carry
 177                  * an acknowledgement number.
 178                  */
 179                 if (dccp->dh_type != 0 && dccp->dh_type != 2) {
 180                         (void) snprintf(line, endline - line, " Ack=%u",
 181                             seq, dccplen);
 182                 }
 183                 line += strlen(line);
 184 
 185                 print_dccpoptions_summary((uchar_t *)dccp + option_offset,
 186                     (uchar_t *)dccp + dccp->dh_offset * 4);
 187         }
 188 
 189 
 190         if (flags & F_DTAIL) {
 191                 show_header("DCCP:  ", "DCCP Header", dccplen);
 192                 show_space();
 193 
 194                 (void) sprintf(get_line((char *)(uintptr_t)dccp->dh_sport -
 195                     dlc_header, 2), "Source port = %d",
 196                     ntohs(dccp->dh_sport));
 197 
 198                 (void) sprintf(get_line((char *)(uintptr_t)dccp->dh_dport -
 199                     dlc_header, 2), "Destination port = %d",
 200                     ntohs(dccp->dh_dport));
 201 
 202                 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_offset -
 203                     dlc_header) + 4, 1), "Data offset = %d bytes",
 204                     dccp->dh_offset * 4);
 205 
 206                 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_ccval -
 207                     dlc_header) + 4, 1), "CCVal = %d",
 208                     dccp->dh_ccval);
 209 
 210                 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_cscov -
 211                     dlc_header) + 4, 1), "Checksum coverage (CsCov) = %d",
 212                     dccp->dh_cscov);
 213 
 214                 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_sum -
 215                     dlc_header) + 4, 1), "Checksum = 0x%04x",
 216                     ntohs(dccp->dh_sum));
 217 
 218                 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_type -
 219                     dlc_header) + 4, 1), "Type = %d (%s)",
 220                     dccp->dh_type, get_type(dccp->dh_type));
 221 
 222                 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_x -
 223                     dlc_header) + 4, 1), "Extended sequence numbers = %d",
 224                     dccp->dh_x);
 225 
 226                 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_seq -
 227                     dlc_header) + 4, 1), "Sequence number = %d",
 228                     seq);
 229 
 230                 /*
 231                  * All packets except DCCP-Request and DCCP-Data carry
 232                  * an acknowledgement number.
 233                  */
 234                 if (dccp->dh_type != 0 && dccp->dh_type != 2) {
 235                 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_seq -
 236                     dlc_header) + 4, 1), "Acknowledgement number = %d",
 237                     seq);
 238                 }
 239 
 240                 print_dccpoptions((uchar_t *)dccp + option_offset,
 241                     (uchar_t *)dccp + dccp->dh_offset * 4);
 242 
 243                 show_space();
 244         }
 245 
 246         return (dccplen);
 247 }
 248 
 249 static void
 250 print_dccpoptions_summary(uchar_t *up, uchar_t *end)
 251 {
 252         uchar_t         *value;
 253         uint8_t         option_type;
 254         uint8_t         option_length;
 255         int             len;
 256         boolean_t       mandatory = B_FALSE;
 257 
 258         while (up != end) {
 259                 option_length = 0;
 260                 option_type = *up++;
 261 
 262                 /*
 263                  * Is this a variable length option?
 264                  */
 265                 if (option_type > 31) {
 266                         option_length = *up++;
 267                         option_length -= 2;
 268                         value = up;
 269 
 270                         up += option_length;
 271                 }
 272                 switch (option_type) {
 273                 case 0:         /* Padding */
 274                         break;
 275                 case 1:         /* Mandatory */
 276                         mandatory = B_TRUE;
 277                         break;
 278                 case 2:         /* Slow receiver */
 279                         break;
 280                 case 3 ... 31:  /* Reserved */
 281                         break;
 282                 case 32:        /* Change L */
 283                         break;
 284                 case 33:        /* Confirm L */
 285                         break;
 286                 case 34:        /* Change R */
 287                         break;
 288                 case 35:        /* Confirm R */
 289                         break;
 290                 case 36:        /* Init cookie */
 291                         break;
 292                 case 37:        /* NDP count */
 293                         break;
 294                 case 38:        /* Ack Vector 0 */
 295                         break;
 296                 case 39:        /* Ack vector 1 */
 297                         break;
 298                 case 40:        /* Data dropped */
 299                         break;
 300                 case 41:        /* Timestamp */
 301                         break;
 302                 case 42:        /* Timestamp echo */
 303                         break;
 304                 case 43:        /* Elapsed time */
 305                         break;
 306                 case 44:        /* Data checksum */
 307                         break;
 308 
 309                 default:
 310                         break;
 311                 }
 312 
 313                 if (option_type != 1) {
 314                         mandatory = B_FALSE;
 315                 }
 316         }
 317 }
 318 
 319 static void
 320 print_dccpoptions(uchar_t *up, uchar_t *end)
 321 {
 322         uchar_t         *value;
 323         uint8_t         option_type;
 324         uint8_t         option_length;
 325         int             len;
 326         boolean_t       mandatory = B_FALSE;
 327 
 328         if (up == end) {
 329                 (void) sprintf(get_line((char *)&up - dlc_header, 1),
 330                      "No options");
 331                 return;
 332         }
 333 
 334         (void) sprintf(get_line((char *)&up - dlc_header, 1),
 335             "Options: (%d bytes)", (int)(end - up));
 336 
 337         while (up != end) {
 338                 option_length = 0;
 339                 option_type = *up++;
 340 
 341                 /*
 342                  * Is this a variable length option?
 343                  */
 344                 if (option_type > 31) {
 345                         option_length = *up++;
 346                         option_length -= 2;
 347                         value = up;
 348 
 349                         up += option_length;
 350                 }
 351 
 352                 switch (option_type) {
 353                 case 0:         /* Padding */
 354                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 355                             dlc_header) + 4, 1), "Padding");
 356                         break;
 357                 case 1:         /* Mandatory */
 358                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 359                             dlc_header) + 4, 1), "Mandatory");
 360                         mandatory = B_TRUE;
 361                         break;
 362                 case 2:         /* Slow receiver */
 363                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 364                             dlc_header) + 4, 1), "Slow receiver");
 365                         break;
 366                 case 3 ... 31:  /* Reserved */
 367                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 368                             dlc_header) + 4, 1), "Reserved");
 369                         break;
 370                 case 32:        /* Change L */
 371                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 372                             dlc_header) + 4, 1), "Change L");
 373                         break;
 374                 case 33:        /* Confirm L */
 375                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 376                             dlc_header) + 4, 1), "Confirm L");
 377                         break;
 378                 case 34:        /* Change R */
 379                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 380                             dlc_header) + 4, 1), "Change R");
 381                         break;
 382                 case 35:        /* Confirm R */
 383                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 384                             dlc_header) + 4, 1), "Confirm R");
 385                         break;
 386                 case 36:        /* Init cookie */
 387                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 388                             dlc_header) + 4, 1), "Init cookie");
 389                         break;
 390                 case 37:        /* NDP count */
 391                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 392                             dlc_header) + 4, 1), "NDP count");
 393                         break;
 394                 case 38:        /* Ack vector 0 */
 395                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 396                             dlc_header) + 4, 1), "Ack vector 0");
 397                         break;
 398                 case 39:        /* Ack vector 1 */
 399                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 400                             dlc_header) + 4, 1), "Ack vector 1");
 401                         break;
 402                 case 40:        /* Data dropped */
 403                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 404                             dlc_header) + 4, 1), "Data dropped");
 405                         break;
 406                 case 41:        /* Timestamp */
 407                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 408                             dlc_header) + 4, 1), "Timestamp");
 409                         break;
 410                 case 42:        /* Timestamp echo */
 411                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 412                             dlc_header) + 4, 1), "TImestamp echo");
 413                         break;
 414                 case 43:        /* Elapsed time */
 415                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 416                             dlc_header) + 4, 1), "Elapsed time");
 417                         break;
 418                 case 44:        /* Data checksum */
 419                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 420                             dlc_header) + 4, 1), "Data checksum");
 421                         break;
 422 
 423                 default:
 424                         (void) sprintf(get_line(((char *)(uintptr_t)up -
 425                             dlc_header) + 4, 1), "Unknown");
 426                         break;
 427                 }
 428 
 429                 if (option_type != 1) {
 430                         mandatory = B_FALSE;
 431                 }
 432         }
 433 }