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