]> The Tcpdump Group git mirrors - tcpdump/blob - print-mptcp.c
Use more the ND_TCHECK_1() macro
[tcpdump] / print-mptcp.c
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 /* \summary: Multipath TCP (MPTCP) printer */
36
37 /* specification: RFC 6824 */
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #include "netdissect-stdinc.h"
44
45 #include "netdissect.h"
46 #include "extract.h"
47 #include "addrtoname.h"
48
49 #include "tcp.h"
50
51 #define MPTCP_SUB_CAPABLE 0x0
52 #define MPTCP_SUB_JOIN 0x1
53 #define MPTCP_SUB_DSS 0x2
54 #define MPTCP_SUB_ADD_ADDR 0x3
55 #define MPTCP_SUB_REMOVE_ADDR 0x4
56 #define MPTCP_SUB_PRIO 0x5
57 #define MPTCP_SUB_FAIL 0x6
58 #define MPTCP_SUB_FCLOSE 0x7
59 #define MPTCP_SUB_TCPRST 0x8
60
61 struct mptcp_option {
62 nd_uint8_t kind;
63 nd_uint8_t len;
64 nd_uint8_t sub_etc; /* subtype upper 4 bits, other stuff lower 4 bits */
65 };
66
67 #define MPTCP_OPT_SUBTYPE(sub_etc) (((sub_etc) >> 4) & 0xF)
68
69 struct mp_capable {
70 nd_uint8_t kind;
71 nd_uint8_t len;
72 nd_uint8_t sub_ver;
73 nd_uint8_t flags;
74 nd_uint64_t sender_key;
75 nd_uint64_t receiver_key;
76 nd_uint16_t data_len;
77 };
78
79 #define MP_CAPABLE_OPT_VERSION(sub_ver) (((sub_ver) >> 0) & 0xF)
80 #define MP_CAPABLE_C 0x80
81 #define MP_CAPABLE_S 0x01
82
83 struct mp_join {
84 nd_uint8_t kind;
85 nd_uint8_t len;
86 nd_uint8_t sub_b;
87 nd_uint8_t addr_id;
88 union {
89 struct {
90 nd_uint32_t token;
91 nd_uint32_t nonce;
92 } syn;
93 struct {
94 nd_uint64_t mac;
95 nd_uint32_t nonce;
96 } synack;
97 struct {
98 nd_byte mac[20];
99 } ack;
100 } u;
101 };
102
103 #define MP_JOIN_B 0x01
104
105 struct mp_dss {
106 nd_uint8_t kind;
107 nd_uint8_t len;
108 nd_uint8_t sub;
109 nd_uint8_t flags;
110 };
111
112 #define MP_DSS_F 0x10
113 #define MP_DSS_m 0x08
114 #define MP_DSS_M 0x04
115 #define MP_DSS_a 0x02
116 #define MP_DSS_A 0x01
117
118 static const struct tok mptcp_addr_subecho_bits[] = {
119 { 0x6, "v0-ip6" },
120 { 0x4, "v0-ip4" },
121 { 0x1, "v1-echo" },
122 { 0x0, "v1" },
123 { 0, NULL }
124 };
125
126 struct mp_add_addr {
127 nd_uint8_t kind;
128 nd_uint8_t len;
129 nd_uint8_t sub_echo;
130 nd_uint8_t addr_id;
131 union {
132 struct {
133 nd_ipv4 addr;
134 nd_uint16_t port;
135 nd_uint64_t mac;
136 } v4;
137 struct {
138 nd_ipv4 addr;
139 nd_uint64_t mac;
140 } v4np;
141 struct {
142 nd_ipv6 addr;
143 nd_uint16_t port;
144 nd_uint64_t mac;
145 } v6;
146 struct {
147 nd_ipv6 addr;
148 nd_uint64_t mac;
149 } v6np;
150 } u;
151 };
152
153 struct mp_remove_addr {
154 nd_uint8_t kind;
155 nd_uint8_t len;
156 nd_uint8_t sub;
157 /* list of addr_id */
158 nd_uint8_t addrs_id[1];
159 };
160
161 struct mp_fail {
162 nd_uint8_t kind;
163 nd_uint8_t len;
164 nd_uint8_t sub;
165 nd_uint8_t resv;
166 nd_uint64_t data_seq;
167 };
168
169 struct mp_close {
170 nd_uint8_t kind;
171 nd_uint8_t len;
172 nd_uint8_t sub;
173 nd_uint8_t rsv;
174 nd_byte key[8];
175 };
176
177 struct mp_prio {
178 nd_uint8_t kind;
179 nd_uint8_t len;
180 nd_uint8_t sub_b;
181 nd_uint8_t addr_id;
182 };
183
184 #define MP_PRIO_B 0x01
185
186 static const struct tok mp_tcprst_flags[] = {
187 { 0x08, "U" },
188 { 0x04, "V" },
189 { 0x02, "W" },
190 { 0x01, "T" },
191 { 0, NULL }
192 };
193
194 static const struct tok mp_tcprst_reasons[] = {
195 { 0x06, "Middlebox interference" },
196 { 0x05, "Unacceptable performance" },
197 { 0x04, "Too much outstanding data" },
198 { 0x03, "Administratively prohibited" },
199 { 0x02, "Lack of resources" },
200 { 0x01, "MPTCP-specific error" },
201 { 0x00, "Unspecified error" },
202 { 0, NULL }
203 };
204
205 struct mp_tcprst {
206 nd_uint8_t kind;
207 nd_uint8_t len;
208 nd_uint8_t sub_b;
209 nd_uint8_t reason;
210 };
211
212 static int
213 dummy_print(netdissect_options *ndo _U_,
214 const u_char *opt _U_, u_int opt_len _U_, u_char flags _U_)
215 {
216 return 1;
217 }
218
219 static int
220 mp_capable_print(netdissect_options *ndo,
221 const u_char *opt, u_int opt_len, u_char flags)
222 {
223 const struct mp_capable *mpc = (const struct mp_capable *) opt;
224 uint8_t version, csum_enabled;
225
226 if (!((opt_len == 12 || opt_len == 4) && flags & TH_SYN) &&
227 !((opt_len == 20 || opt_len == 22 || opt_len == 24) && (flags & (TH_SYN | TH_ACK)) ==
228 TH_ACK))
229 return 0;
230
231 version = MP_CAPABLE_OPT_VERSION(GET_U_1(mpc->sub_ver));
232 switch (version) {
233 case 0: /* fall through */
234 case 1:
235 ND_PRINT(" v%u", version);
236 break;
237 default:
238 ND_PRINT(" Unknown Version (%u)", version);
239 return 1;
240 }
241
242 csum_enabled = GET_U_1(mpc->flags) & MP_CAPABLE_C;
243 if (csum_enabled)
244 ND_PRINT(" csum");
245 if (opt_len == 12 || opt_len >= 20) {
246 ND_PRINT(" {0x%" PRIx64, GET_BE_U_8(mpc->sender_key));
247 if (opt_len >= 20)
248 ND_PRINT(",0x%" PRIx64, GET_BE_U_8(mpc->receiver_key));
249
250 /* RFC 8684 Section 3.1 */
251 if ((opt_len == 22 && !csum_enabled) || opt_len == 24)
252 ND_PRINT(",data_len=%u", GET_BE_U_2(mpc->data_len));
253 ND_PRINT("}");
254 }
255 return 1;
256 }
257
258 static int
259 mp_join_print(netdissect_options *ndo,
260 const u_char *opt, u_int opt_len, u_char flags)
261 {
262 const struct mp_join *mpj = (const struct mp_join *) opt;
263
264 if (!(opt_len == 12 && (flags & TH_SYN)) &&
265 !(opt_len == 16 && (flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) &&
266 !(opt_len == 24 && (flags & TH_ACK)))
267 return 0;
268
269 if (opt_len != 24) {
270 if (GET_U_1(mpj->sub_b) & MP_JOIN_B)
271 ND_PRINT(" backup");
272 ND_PRINT(" id %u", GET_U_1(mpj->addr_id));
273 }
274
275 switch (opt_len) {
276 case 12: /* SYN */
277 ND_PRINT(" token 0x%x" " nonce 0x%x",
278 GET_BE_U_4(mpj->u.syn.token),
279 GET_BE_U_4(mpj->u.syn.nonce));
280 break;
281 case 16: /* SYN/ACK */
282 ND_PRINT(" hmac 0x%" PRIx64 " nonce 0x%x",
283 GET_BE_U_8(mpj->u.synack.mac),
284 GET_BE_U_4(mpj->u.synack.nonce));
285 break;
286 case 24: {/* ACK */
287 size_t i;
288 ND_PRINT(" hmac 0x");
289 for (i = 0; i < sizeof(mpj->u.ack.mac); ++i)
290 ND_PRINT("%02x", mpj->u.ack.mac[i]);
291 }
292 default:
293 break;
294 }
295 return 1;
296 }
297
298 static int
299 mp_dss_print(netdissect_options *ndo,
300 const u_char *opt, u_int opt_len, u_char flags)
301 {
302 const struct mp_dss *mdss = (const struct mp_dss *) opt;
303 uint8_t mdss_flags;
304
305 /* We need the flags, at a minimum. */
306 if (opt_len < 4)
307 return 0;
308
309 if (flags & TH_SYN)
310 return 0;
311
312 mdss_flags = GET_U_1(mdss->flags);
313 if (mdss_flags & MP_DSS_F)
314 ND_PRINT(" fin");
315
316 opt += 4;
317 opt_len -= 4;
318 if (mdss_flags & MP_DSS_A) {
319 /* Ack present */
320 ND_PRINT(" ack ");
321 /*
322 * If the a flag is set, we have an 8-byte ack; if it's
323 * clear, we have a 4-byte ack.
324 */
325 if (mdss_flags & MP_DSS_a) {
326 if (opt_len < 8)
327 return 0;
328 ND_PRINT("%" PRIu64, GET_BE_U_8(opt));
329 opt += 8;
330 opt_len -= 8;
331 } else {
332 if (opt_len < 4)
333 return 0;
334 ND_PRINT("%u", GET_BE_U_4(opt));
335 opt += 4;
336 opt_len -= 4;
337 }
338 }
339
340 if (mdss_flags & MP_DSS_M) {
341 /*
342 * Data Sequence Number (DSN), Subflow Sequence Number (SSN),
343 * Data-Level Length present, and Checksum possibly present.
344 */
345 ND_PRINT(" seq ");
346 /*
347 * If the m flag is set, we have an 8-byte NDS; if it's clear,
348 * we have a 4-byte DSN.
349 */
350 if (mdss_flags & MP_DSS_m) {
351 if (opt_len < 8)
352 return 0;
353 ND_PRINT("%" PRIu64, GET_BE_U_8(opt));
354 opt += 8;
355 opt_len -= 8;
356 } else {
357 if (opt_len < 4)
358 return 0;
359 ND_PRINT("%u", GET_BE_U_4(opt));
360 opt += 4;
361 opt_len -= 4;
362 }
363 if (opt_len < 4)
364 return 0;
365 ND_PRINT(" subseq %u", GET_BE_U_4(opt));
366 opt += 4;
367 opt_len -= 4;
368 if (opt_len < 2)
369 return 0;
370 ND_PRINT(" len %u", GET_BE_U_2(opt));
371 opt += 2;
372 opt_len -= 2;
373
374 /*
375 * The Checksum is present only if negotiated.
376 * If there are at least 2 bytes left, process the next 2
377 * bytes as the Checksum.
378 */
379 if (opt_len >= 2) {
380 ND_PRINT(" csum 0x%x", GET_BE_U_2(opt));
381 opt_len -= 2;
382 }
383 }
384 if (opt_len != 0)
385 return 0;
386 return 1;
387 }
388
389 static int
390 add_addr_print(netdissect_options *ndo,
391 const u_char *opt, u_int opt_len, u_char flags _U_)
392 {
393 const struct mp_add_addr *add_addr = (const struct mp_add_addr *) opt;
394
395 if (!(opt_len == 8 || opt_len == 10 || opt_len == 16 || opt_len == 18 ||
396 opt_len == 20 || opt_len == 22 || opt_len == 28 || opt_len == 30))
397 return 0;
398
399 ND_PRINT(" %s",
400 tok2str(mptcp_addr_subecho_bits, "[bad version/echo]",
401 GET_U_1(add_addr->sub_echo) & 0xF));
402 ND_PRINT(" id %u", GET_U_1(add_addr->addr_id));
403 if (opt_len == 8 || opt_len == 10 || opt_len == 16 || opt_len == 18) {
404 ND_PRINT(" %s", GET_IPADDR_STRING(add_addr->u.v4.addr));
405 if (opt_len == 10 || opt_len == 18)
406 ND_PRINT(":%u", GET_BE_U_2(add_addr->u.v4.port));
407 if (opt_len == 16)
408 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v4np.mac));
409 if (opt_len == 18)
410 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v4.mac));
411 }
412
413 if (opt_len == 20 || opt_len == 22 || opt_len == 28 || opt_len == 30) {
414 ND_PRINT(" %s", GET_IP6ADDR_STRING(add_addr->u.v6.addr));
415 if (opt_len == 22 || opt_len == 30)
416 ND_PRINT(":%u", GET_BE_U_2(add_addr->u.v6.port));
417 if (opt_len == 28)
418 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v6np.mac));
419 if (opt_len == 30)
420 ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v6.mac));
421 }
422
423 return 1;
424 }
425
426 static int
427 remove_addr_print(netdissect_options *ndo,
428 const u_char *opt, u_int opt_len, u_char flags _U_)
429 {
430 const struct mp_remove_addr *remove_addr = (const struct mp_remove_addr *) opt;
431 u_int i;
432
433 if (opt_len < 4)
434 return 0;
435
436 opt_len -= 3;
437 ND_PRINT(" id");
438 for (i = 0; i < opt_len; i++)
439 ND_PRINT(" %u", GET_U_1(remove_addr->addrs_id[i]));
440 return 1;
441 }
442
443 static int
444 mp_prio_print(netdissect_options *ndo,
445 const u_char *opt, u_int opt_len, u_char flags _U_)
446 {
447 const struct mp_prio *mpp = (const struct mp_prio *) opt;
448
449 if (opt_len != 3 && opt_len != 4)
450 return 0;
451
452 if (GET_U_1(mpp->sub_b) & MP_PRIO_B)
453 ND_PRINT(" backup");
454 else
455 ND_PRINT(" non-backup");
456 if (opt_len == 4)
457 ND_PRINT(" id %u", GET_U_1(mpp->addr_id));
458
459 return 1;
460 }
461
462 static int
463 mp_fail_print(netdissect_options *ndo,
464 const u_char *opt, u_int opt_len, u_char flags _U_)
465 {
466 if (opt_len != 12)
467 return 0;
468
469 ND_PRINT(" seq %" PRIu64, GET_BE_U_8(opt + 4));
470 return 1;
471 }
472
473 static int
474 mp_fast_close_print(netdissect_options *ndo,
475 const u_char *opt, u_int opt_len, u_char flags _U_)
476 {
477 if (opt_len != 12)
478 return 0;
479
480 ND_PRINT(" key 0x%" PRIx64, GET_BE_U_8(opt + 4));
481 return 1;
482 }
483
484 static int
485 mp_tcprst_print(netdissect_options *ndo,
486 const u_char *opt, u_int opt_len, u_char flags _U_)
487 {
488 const struct mp_tcprst *mpr = (const struct mp_tcprst *)opt;
489
490 if (opt_len != 4)
491 return 0;
492
493 ND_PRINT(" flags [%s]", bittok2str_nosep(mp_tcprst_flags, "none",
494 GET_U_1(mpr->sub_b)));
495
496 ND_PRINT(" reason %s", tok2str(mp_tcprst_reasons, "unknown (0x%02x)",
497 GET_U_1(mpr->reason)));
498 return 1;
499 }
500
501 static const struct {
502 const char *name;
503 int (*print)(netdissect_options *, const u_char *, u_int, u_char);
504 } mptcp_options[] = {
505 { "capable", mp_capable_print },
506 { "join", mp_join_print },
507 { "dss", mp_dss_print },
508 { "add-addr", add_addr_print },
509 { "rem-addr", remove_addr_print },
510 { "prio", mp_prio_print },
511 { "fail", mp_fail_print },
512 { "fast-close", mp_fast_close_print },
513 { "tcprst", mp_tcprst_print },
514 { "unknown", dummy_print },
515 };
516
517 int
518 mptcp_print(netdissect_options *ndo,
519 const u_char *cp, u_int len, u_char flags)
520 {
521 const struct mptcp_option *opt;
522 u_int subtype;
523
524 ndo->ndo_protocol = "mptcp";
525 if (len < 3)
526 return 0;
527
528 opt = (const struct mptcp_option *) cp;
529 subtype = MPTCP_OPT_SUBTYPE(GET_U_1(opt->sub_etc));
530 subtype = ND_MIN(subtype, MPTCP_SUB_TCPRST + 1);
531
532 ND_PRINT(" %u", len);
533
534 ND_PRINT(" %s", mptcp_options[subtype].name);
535 return mptcp_options[subtype].print(ndo, cp, len, flags);
536 }