print-mptcp.c revision 303975
1/**
2 * Copyright (c) 2012
3 *
4 * Gregory Detal <gregory.detal@uclouvain.be>
5 * Christoph Paasch <christoph.paasch@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
57struct 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
65struct 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
78struct 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
100struct 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
113struct 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
132struct 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
140struct 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
148struct 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
156struct 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
165static int
166dummy_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
172static int
173mp_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
196static int
197mp_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
236static 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
264static int
265mp_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
309static int
310add_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
341static int
342remove_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
358static int
359mp_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
377static int
378mp_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
388static int
389mp_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
399static 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
414int
415mptcp_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