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 #define NETDISSECT_REWORKED
     36 #ifdef HAVE_CONFIG_H
     37 #include "config.h"
     38 #endif
     39 
     40 #include <tcpdump-stdinc.h>
     41 
     42 #include "interface.h"
     43 #include "extract.h"
     44 #include "addrtoname.h"
     45 
     46 #include "tcp.h"
     47 
     48 #define MPTCP_SUB_CAPABLE       0x0
     49 #define MPTCP_SUB_JOIN          0x1
     50 #define MPTCP_SUB_DSS           0x2
     51 #define MPTCP_SUB_ADD_ADDR      0x3
     52 #define MPTCP_SUB_REMOVE_ADDR   0x4
     53 #define MPTCP_SUB_PRIO          0x5
     54 #define MPTCP_SUB_FAIL          0x6
     55 #define MPTCP_SUB_FCLOSE        0x7
     56 
     57 struct mptcp_option {
     58         uint8_t        kind;
     59         uint8_t        len;
     60         uint8_t        sub_etc;        /* subtype upper 4 bits, other stuff lower 4 bits */
     61 };
     62 
     63 #define MPTCP_OPT_SUBTYPE(sub_etc)      (((sub_etc) >> 4) & 0xF)
     64 
     65 struct mp_capable {
     66         uint8_t        kind;
     67         uint8_t        len;
     68         uint8_t        sub_ver;
     69         uint8_t        flags;
     70         uint8_t        sender_key[8];
     71         uint8_t        receiver_key[8];
     72 };
     73 
     74 #define MP_CAPABLE_OPT_VERSION(sub_ver) (((sub_ver) >> 0) & 0xF)
     75 #define MP_CAPABLE_C                    0x80
     76 #define MP_CAPABLE_S                    0x01
     77 
     78 struct mp_join {
     79         uint8_t        kind;
     80         uint8_t        len;
     81         uint8_t        sub_b;
     82         uint8_t        addr_id;
     83         union {
     84                 struct {
     85                         uint8_t         token[4];
     86                         uint8_t         nonce[4];
     87                 } syn;
     88                 struct {
     89                         uint8_t         mac[8];
     90                         uint8_t         nonce[4];
     91                 } synack;
     92                 struct {
     93                         uint8_t        mac[20];
     94                 } ack;
     95         } u;
     96 };
     97 
     98 #define MP_JOIN_B                       0x01
     99 
    100 struct mp_dss {
    101         uint8_t        kind;
    102         uint8_t        len;
    103         uint8_t        sub;
    104         uint8_t        flags;
    105 };
    106 
    107 #define MP_DSS_F                        0x10
    108 #define MP_DSS_m                        0x08
    109 #define MP_DSS_M                        0x04
    110 #define MP_DSS_a                        0x02
    111 #define MP_DSS_A                        0x01
    112 
    113 struct mp_add_addr {
    114         uint8_t        kind;
    115         uint8_t        len;
    116         uint8_t        sub_ipver;
    117         uint8_t        addr_id;
    118         union {
    119                 struct {
    120                         uint8_t         addr[4];
    121                         uint8_t         port[2];
    122                 } v4;
    123                 struct {
    124                         uint8_t         addr[16];
    125                         uint8_t         port[2];
    126                 } v6;
    127         } u;
    128 };
    129 
    130 #define MP_ADD_ADDR_IPVER(sub_ipver)    (((sub_ipver) >> 0) & 0xF)
    131 
    132 struct mp_remove_addr {
    133         uint8_t        kind;
    134         uint8_t        len;
    135         uint8_t        sub;
    136         /* list of addr_id */
    137         uint8_t        addrs_id;
    138 };
    139 
    140 struct mp_fail {
    141         uint8_t        kind;
    142         uint8_t        len;
    143         uint8_t        sub;
    144         uint8_t        resv;
    145         uint8_t        data_seq[8];
    146 };
    147 
    148 struct mp_close {
    149         uint8_t        kind;
    150         uint8_t        len;
    151         uint8_t        sub;
    152         uint8_t        rsv;
    153         uint8_t        key[8];
    154 };
    155 
    156 struct mp_prio {
    157         uint8_t        kind;
    158         uint8_t        len;
    159         uint8_t        sub_b;
    160         uint8_t        addr_id;
    161 };
    162 
    163 #define MP_PRIO_B                       0x01
    164 
    165 static int
    166 dummy_print(netdissect_options *ndo _U_,
    167             const u_char *opt _U_, u_int opt_len _U_, u_char flags _U_)
    168 {
    169         return 1;
    170 }
    171 
    172 static int
    173 mp_capable_print(netdissect_options *ndo,
    174                  const u_char *opt, u_int opt_len, u_char flags)
    175 {
    176         struct mp_capable *mpc = (struct mp_capable *) opt;
    177 
    178         if (!(opt_len == 12 && flags & TH_SYN) &&
    179             !(opt_len == 20 && (flags & (TH_SYN | TH_ACK)) == TH_ACK))
    180                 return 0;
    181 
    182         if (MP_CAPABLE_OPT_VERSION(mpc->sub_ver) != 0) {
    183                 ND_PRINT((ndo, " Unknown Version (%d)", MP_CAPABLE_OPT_VERSION(mpc->sub_ver)));
    184                 return 1;
    185         }
    186 
    187         if (mpc->flags & MP_CAPABLE_C)
    188                 ND_PRINT((ndo, " csum"));
    189         ND_PRINT((ndo, " {0x%" PRIx64, EXTRACT_64BITS(mpc->sender_key)));
    190         if (opt_len == 20) /* ACK */
    191                 ND_PRINT((ndo, ",0x%" PRIx64, EXTRACT_64BITS(mpc->receiver_key)));
    192         ND_PRINT((ndo, "}"));
    193         return 1;
    194 }
    195 
    196 static int
    197 mp_join_print(netdissect_options *ndo,
    198               const u_char *opt, u_int opt_len, u_char flags)
    199 {
    200         struct mp_join *mpj = (struct mp_join *) opt;
    201 
    202         if (!(opt_len == 12 && flags & TH_SYN) &&
    203             !(opt_len == 16 && (flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) &&
    204             !(opt_len == 24 && flags & TH_ACK))
    205                 return 0;
    206 
    207         if (opt_len != 24) {
    208                 if (mpj->sub_b & MP_JOIN_B)
    209                         ND_PRINT((ndo, " backup"));
    210                 ND_PRINT((ndo, " id %u", mpj->addr_id));
    211         }
    212 
    213         switch (opt_len) {
    214         case 12: /* SYN */
    215                 ND_PRINT((ndo, " token 0x%x" " nonce 0x%x",
    216                         EXTRACT_32BITS(mpj->u.syn.token),
    217                         EXTRACT_32BITS(mpj->u.syn.nonce)));
    218                 break;
    219         case 16: /* SYN/ACK */
    220                 ND_PRINT((ndo, " hmac 0x%" PRIx64 " nonce 0x%x",
    221                         EXTRACT_64BITS(mpj->u.synack.mac),
    222                         EXTRACT_32BITS(mpj->u.synack.nonce)));
    223                 break;
    224         case 24: {/* ACK */
    225                 size_t i;
    226                 ND_PRINT((ndo, " hmac 0x"));
    227                 for (i = 0; i < sizeof(mpj->u.ack.mac); ++i)
    228                         ND_PRINT((ndo, "%02x", mpj->u.ack.mac[i]));
    229         }
    230         default:
    231                 break;
    232         }
    233         return 1;
    234 }
    235 
    236 static u_int mp_dss_len(struct mp_dss *m, int csum)
    237 {
    238         u_int len;
    239 
    240         len = 4;
    241         if (m->flags & MP_DSS_A) {
    242                 /* Ack present - 4 or 8 octets */
    243                 len += (m->flags & MP_DSS_a) ? 8 : 4;
    244         }
    245         if (m->flags & MP_DSS_M) {
    246                 /*
    247                  * Data Sequence Number (DSN), Subflow Sequence Number (SSN),
    248                  * Data-Level Length present, and Checksum possibly present.
    249                  * All but the Checksum are 10 bytes if the m flag is
    250                  * clear (4-byte DSN) and 14 bytes if the m flag is set
    251                  * (8-byte DSN).
    252                  */
    253                 len += (m->flags & MP_DSS_m) ? 14 : 10;
    254 
    255                 /*
    256                  * The Checksum is present only if negotiated.
    257                  */
    258                 if (csum)
    259                         len += 2;
    260 	}
    261 	return len;
    262 }
    263 
    264 static int
    265 mp_dss_print(netdissect_options *ndo,
    266              const u_char *opt, u_int opt_len, u_char flags)
    267 {
    268         struct mp_dss *mdss = (struct mp_dss *) opt;
    269 
    270         if ((opt_len != mp_dss_len(mdss, 1) &&
    271              opt_len != mp_dss_len(mdss, 0)) || flags & TH_SYN)
    272                 return 0;
    273 
    274         if (mdss->flags & MP_DSS_F)
    275                 ND_PRINT((ndo, " fin"));
    276 
    277         opt += 4;
    278         if (mdss->flags & MP_DSS_A) {
    279                 ND_PRINT((ndo, " ack "));
    280                 if (mdss->flags & MP_DSS_a) {
    281                         ND_PRINT((ndo, "%" PRIu64, EXTRACT_64BITS(opt)));
    282                         opt += 8;
    283                 } else {
    284                         ND_PRINT((ndo, "%u", EXTRACT_32BITS(opt)));
    285                         opt += 4;
    286                 }
    287         }
    288 
    289         if (mdss->flags & MP_DSS_M) {
    290                 ND_PRINT((ndo, " seq "));
    291                 if (mdss->flags & MP_DSS_m) {
    292                         ND_PRINT((ndo, "%" PRIu64, EXTRACT_64BITS(opt)));
    293                         opt += 8;
    294                 } else {
    295                         ND_PRINT((ndo, "%u", EXTRACT_32BITS(opt)));
    296                         opt += 4;
    297                 }
    298                 ND_PRINT((ndo, " subseq %u", EXTRACT_32BITS(opt)));
    299                 opt += 4;
    300                 ND_PRINT((ndo, " len %u", EXTRACT_16BITS(opt)));
    301                 opt += 2;
    302 
    303                 if (opt_len == mp_dss_len(mdss, 1))
    304                         ND_PRINT((ndo, " csum 0x%x", EXTRACT_16BITS(opt)));
    305         }
    306         return 1;
    307 }
    308 
    309 static int
    310 add_addr_print(netdissect_options *ndo,
    311                const u_char *opt, u_int opt_len, u_char flags _U_)
    312 {
    313         struct mp_add_addr *add_addr = (struct mp_add_addr *) opt;
    314         u_int ipver = MP_ADD_ADDR_IPVER(add_addr->sub_ipver);
    315 
    316         if (!((opt_len == 8 || opt_len == 10) && ipver == 4) &&
    317             !((opt_len == 20 || opt_len == 22) && ipver == 6))
    318                 return 0;
    319 
    320         ND_PRINT((ndo, " id %u", add_addr->addr_id));
    321         switch (ipver) {
    322         case 4:
    323                 ND_PRINT((ndo, " %s", ipaddr_string(ndo, add_addr->u.v4.addr)));
    324                 if (opt_len == 10)
    325                         ND_PRINT((ndo, ":%u", EXTRACT_16BITS(add_addr->u.v4.port)));
    326                 break;
    327         case 6:
    328 #ifdef INET6
    329                 ND_PRINT((ndo, " %s", ip6addr_string(ndo, add_addr->u.v6.addr)));
    330 #endif
    331                 if (opt_len == 22)
    332                         ND_PRINT((ndo, ":%u", EXTRACT_16BITS(add_addr->u.v6.port)));
    333                 break;
    334         default:
    335                 return 0;
    336         }
    337 
    338         return 1;
    339 }
    340 
    341 static int
    342 remove_addr_print(netdissect_options *ndo,
    343                   const u_char *opt, u_int opt_len, u_char flags _U_)
    344 {
    345         struct mp_remove_addr *remove_addr = (struct mp_remove_addr *) opt;
    346         uint8_t *addr_id = &remove_addr->addrs_id;
    347 
    348         if (opt_len < 4)
    349                 return 0;
    350 
    351         opt_len -= 3;
    352         ND_PRINT((ndo, " id"));
    353         while (opt_len--)
    354                 ND_PRINT((ndo, " %u", *addr_id++));
    355         return 1;
    356 }
    357 
    358 static int
    359 mp_prio_print(netdissect_options *ndo,
    360               const u_char *opt, u_int opt_len, u_char flags _U_)
    361 {
    362         struct mp_prio *mpp = (struct mp_prio *) opt;
    363 
    364         if (opt_len != 3 && opt_len != 4)
    365                 return 0;
    366 
    367         if (mpp->sub_b & MP_PRIO_B)
    368                 ND_PRINT((ndo, " backup"));
    369         else
    370                 ND_PRINT((ndo, " non-backup"));
    371         if (opt_len == 4)
    372                 ND_PRINT((ndo, " id %u", mpp->addr_id));
    373 
    374         return 1;
    375 }
    376 
    377 static int
    378 mp_fail_print(netdissect_options *ndo,
    379               const u_char *opt, u_int opt_len, u_char flags _U_)
    380 {
    381         if (opt_len != 12)
    382                 return 0;
    383 
    384         ND_PRINT((ndo, " seq %" PRIu64, EXTRACT_64BITS(opt + 4)));
    385         return 1;
    386 }
    387 
    388 static int
    389 mp_fast_close_print(netdissect_options *ndo,
    390                     const u_char *opt, u_int opt_len, u_char flags _U_)
    391 {
    392         if (opt_len != 12)
    393                 return 0;
    394 
    395         ND_PRINT((ndo, " key 0x%" PRIx64, EXTRACT_64BITS(opt + 4)));
    396         return 1;
    397 }
    398 
    399 static const struct {
    400         const char *name;
    401         int (*print)(netdissect_options *, const u_char *, u_int, u_char);
    402 } mptcp_options[] = {
    403         { "capable", mp_capable_print},
    404         { "join",       mp_join_print },
    405         { "dss",        mp_dss_print },
    406         { "add-addr",   add_addr_print },
    407         { "rem-addr",   remove_addr_print },
    408         { "prio",       mp_prio_print },
    409         { "fail",       mp_fail_print },
    410         { "fast-close", mp_fast_close_print },
    411         { "unknown",    dummy_print },
    412 };
    413 
    414 int
    415 mptcp_print(netdissect_options *ndo,
    416             const u_char *cp, u_int len, u_char flags)
    417 {
    418         struct mptcp_option *opt;
    419         u_int subtype;
    420 
    421         if (len < 3)
    422                 return 0;
    423 
    424         opt = (struct mptcp_option *) cp;
    425         subtype = min(MPTCP_OPT_SUBTYPE(opt->sub_etc), MPTCP_SUB_FCLOSE + 1);
    426 
    427         ND_PRINT((ndo, " %s", mptcp_options[subtype].name));
    428         return mptcp_options[subtype].print(ndo, cp, len, flags);
    429 }
    430