xref: /freebsd/contrib/tcpdump/print-mptcp.c (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
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 
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