Home | History | Annotate | Download | only in tcpdump
      1 /**
      2  * Copyright (c) 2012
      3  *
      4  * Gregory Detal <gregory.detal (at) uclouvain.be>
      5  * Christoph Paasch <christoph.paasch (at) uclouvain.be>
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  *
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  *
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * 3. Neither the name of the University nor of the Laboratory may be used
     19  *    to endorse or promote products derived from this software without
     20  *    specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #ifdef HAVE_CONFIG_H
     36 #include "config.h"
     37 #endif
     38 
     39 #include <tcpdump-stdinc.h>
     40 
     41 #include <stdio.h>
     42 #include <string.h>
     43 
     44 #include "interface.h"
     45 #include "extract.h"
     46 #include "addrtoname.h"
     47 
     48 #include "ipproto.h"
     49 #include "mptcp.h"
     50 #include "tcp.h"
     51 
     52 static int dummy_print(const u_char *opt _U_, u_int opt_len _U_, u_char flags _U_)
     53 {
     54         return 1;
     55 }
     56 
     57 static int mp_capable_print(const u_char *opt, u_int opt_len, u_char flags)
     58 {
     59         struct mp_capable *mpc = (struct mp_capable *) opt;
     60 
     61         if (!(opt_len == 12 && flags & TH_SYN) &&
     62             !(opt_len == 20 && (flags & (TH_SYN | TH_ACK)) == TH_ACK))
     63                 return 0;
     64 
     65         if (MP_CAPABLE_OPT_VERSION(mpc->sub_ver) != 0) {
     66                 printf(" Unknown Version (%d)", MP_CAPABLE_OPT_VERSION(mpc->sub_ver));
     67                 return 1;
     68         }
     69 
     70         if (mpc->flags & MP_CAPABLE_C)
     71                 printf(" csum");
     72         printf(" {0x%" PRIx64, EXTRACT_64BITS(mpc->sender_key));
     73         if (opt_len == 20) /* ACK */
     74                 printf(",0x%" PRIx64, EXTRACT_64BITS(mpc->receiver_key));
     75         printf("}");
     76         return 1;
     77 }
     78 
     79 static int mp_join_print(const u_char *opt, u_int opt_len, u_char flags)
     80 {
     81         struct mp_join *mpj = (struct mp_join *) opt;
     82 
     83         if (!(opt_len == 12 && flags & TH_SYN) &&
     84             !(opt_len == 16 && (flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) &&
     85             !(opt_len == 24 && flags & TH_ACK))
     86                 return 0;
     87 
     88         if (opt_len != 24) {
     89                 if (mpj->sub_b & MP_JOIN_B)
     90                         printf(" backup");
     91                 printf(" id %u", mpj->addr_id);
     92         }
     93 
     94         switch (opt_len) {
     95         case 12: /* SYN */
     96                 printf(" token 0x%x" " nonce 0x%x",
     97                         EXTRACT_32BITS(mpj->u.syn.token),
     98                         EXTRACT_32BITS(mpj->u.syn.nonce));
     99                 break;
    100         case 16: /* SYN/ACK */
    101                 printf(" hmac 0x%" PRIx64 " nonce 0x%x",
    102                         EXTRACT_64BITS(mpj->u.synack.mac),
    103                         EXTRACT_32BITS(mpj->u.synack.nonce));
    104                 break;
    105         case 24: {/* ACK */
    106                 size_t i;
    107                 printf(" hmac 0x");
    108                 for (i = 0; i < sizeof(mpj->u.ack.mac); ++i)
    109                         printf("%02x", mpj->u.ack.mac[i]);
    110         }
    111         default:
    112                 break;
    113         }
    114         return 1;
    115 }
    116 
    117 static u_int mp_dss_len(struct mp_dss *m, int csum)
    118 {
    119         u_int len;
    120 
    121         len = 4;
    122         if (m->flags & MP_DSS_A) {
    123                 /* Ack present - 4 or 8 octets */
    124                 len += (m->flags & MP_DSS_a) ? 8 : 4;
    125         }
    126         if (m->flags & MP_DSS_M) {
    127                 /*
    128                  * Data Sequence Number (DSN), Subflow Sequence Number (SSN),
    129                  * Data-Level Length present, and Checksum possibly present.
    130                  * All but the Checksum are 10 bytes if the m flag is
    131                  * clear (4-byte DSN) and 14 bytes if the m flag is set
    132                  * (8-byte DSN).
    133                  */
    134                 len += (m->flags & MP_DSS_m) ? 14 : 10;
    135 
    136                 /*
    137                  * The Checksum is present only if negotiated.
    138                  */
    139                 if (csum)
    140                         len += 2;
    141 	}
    142 	return len;
    143 }
    144 
    145 static int mp_dss_print(const u_char *opt, u_int opt_len, u_char flags)
    146 {
    147         struct mp_dss *mdss = (struct mp_dss *) opt;
    148 
    149         if ((opt_len != mp_dss_len(mdss, 1) &&
    150              opt_len != mp_dss_len(mdss, 0)) || flags & TH_SYN)
    151                 return 0;
    152 
    153         if (mdss->flags & MP_DSS_F)
    154                 printf(" fin");
    155 
    156         opt += 4;
    157         if (mdss->flags & MP_DSS_A) {
    158                 printf(" ack ");
    159                 if (mdss->flags & MP_DSS_a) {
    160                         printf("%" PRIu64, EXTRACT_64BITS(opt));
    161                         opt += 8;
    162                 } else {
    163                         printf("%u", EXTRACT_32BITS(opt));
    164                         opt += 4;
    165                 }
    166         }
    167 
    168         if (mdss->flags & MP_DSS_M) {
    169                 printf(" seq ");
    170                 if (mdss->flags & MP_DSS_m) {
    171                         printf("%" PRIu64, EXTRACT_64BITS(opt));
    172                         opt += 8;
    173                 } else {
    174                         printf("%u", EXTRACT_32BITS(opt));
    175                         opt += 4;
    176                 }
    177                 printf(" subseq %u", EXTRACT_32BITS(opt));
    178                 opt += 4;
    179                 printf(" len %u", EXTRACT_16BITS(opt));
    180                 opt += 2;
    181 
    182                 if (opt_len == mp_dss_len(mdss, 1))
    183                         printf(" csum 0x%x", EXTRACT_16BITS(opt));
    184         }
    185         return 1;
    186 }
    187 
    188 static int add_addr_print(const u_char *opt, u_int opt_len, u_char flags _U_)
    189 {
    190         struct mp_add_addr *add_addr = (struct mp_add_addr *) opt;
    191         u_int ipver = MP_ADD_ADDR_IPVER(add_addr->sub_ipver);
    192 
    193         if (!((opt_len == 8 || opt_len == 10) && ipver == 4) &&
    194             !((opt_len == 20 || opt_len == 22) && ipver == 6))
    195                 return 0;
    196 
    197         printf(" id %u", add_addr->addr_id);
    198         switch (ipver) {
    199         case 4:
    200                 printf(" %s", ipaddr_string(add_addr->u.v4.addr));
    201                 if (opt_len == 10)
    202                         printf(":%u", EXTRACT_16BITS(add_addr->u.v4.port));
    203                 break;
    204         case 6:
    205 #ifdef INET6
    206                 printf(" %s", ip6addr_string(add_addr->u.v6.addr));
    207 #endif
    208                 if (opt_len == 22)
    209                         printf(":%u", EXTRACT_16BITS(add_addr->u.v6.port));
    210                 break;
    211         default:
    212                 return 0;
    213         }
    214 
    215         return 1;
    216 }
    217 
    218 static int remove_addr_print(const u_char *opt, u_int opt_len, u_char flags _U_)
    219 {
    220         struct mp_remove_addr *remove_addr = (struct mp_remove_addr *) opt;
    221         u_int8_t *addr_id = &remove_addr->addrs_id;
    222 
    223         if (opt_len < 4)
    224                 return 0;
    225 
    226         opt_len -= 3;
    227         printf(" id");
    228         while (opt_len--)
    229                 printf(" %u", *addr_id++);
    230         return 1;
    231 }
    232 
    233 static int mp_prio_print(const u_char *opt, u_int opt_len, u_char flags _U_)
    234 {
    235         struct mp_prio *mpp = (struct mp_prio *) opt;
    236 
    237         if (opt_len != 3 && opt_len != 4)
    238                 return 0;
    239 
    240         if (mpp->sub_b & MP_PRIO_B)
    241                 printf(" backup");
    242         else
    243                 printf(" non-backup");
    244         if (opt_len == 4)
    245                 printf(" id %u", mpp->addr_id);
    246 
    247         return 1;
    248 }
    249 
    250 static int mp_fail_print(const u_char *opt, u_int opt_len, u_char flags _U_)
    251 {
    252         if (opt_len != 12)
    253                 return 0;
    254 
    255         printf(" seq %" PRIu64, EXTRACT_64BITS(opt + 4));
    256         return 1;
    257 }
    258 
    259 static int mp_fast_close_print(const u_char *opt, u_int opt_len, u_char flags _U_)
    260 {
    261         if (opt_len != 12)
    262                 return 0;
    263 
    264         printf(" key 0x%" PRIx64, EXTRACT_64BITS(opt + 4));
    265         return 1;
    266 }
    267 
    268 static struct {
    269         const char *name;
    270         int (*print)(const u_char *, u_int, u_char);
    271 } mptcp_options[] = {
    272         { "capable", mp_capable_print},
    273         { "join",       mp_join_print },
    274         { "dss",        mp_dss_print },
    275         { "add-addr",   add_addr_print },
    276         { "rem-addr",   remove_addr_print },
    277         { "prio",       mp_prio_print },
    278         { "fail",       mp_fail_print },
    279         { "fast-close", mp_fast_close_print },
    280         { "unknown",    dummy_print },
    281 };
    282 
    283 int mptcp_print(const u_char *cp, u_int len, u_char flags)
    284 {
    285         struct mptcp_option *opt;
    286         u_int subtype;
    287 
    288         if (len < 3)
    289                 return 0;
    290 
    291         opt = (struct mptcp_option *) cp;
    292         subtype = min(MPTCP_OPT_SUBTYPE(opt->sub_etc), MPTCP_SUB_FCLOSE + 1);
    293 
    294         printf(" %s", mptcp_options[subtype].name);
    295         return mptcp_options[subtype].print(cp, len, flags);
    296 }
    297